subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1546837 [2/2] - in /subversion/branches/fsfs-improvements: ./ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs/ subversion/libsvn_...
Date Sun, 01 Dec 2013 18:51:28 GMT
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c Sun Dec  1 18:51:26 2013
@@ -259,11 +259,6 @@ svn_stream_printf_from_utf8(svn_stream_t
   return svn_error_trace(svn_stream_puts(stream, translated));
 }
 
-/* Size that 90% of the lines we encounter will be not longer than.
-   used by stream_readline_bytewise() and stream_readline_chunky().
- */
-#define LINE_CHUNK_SIZE 80
-
 /* Guts of svn_stream_readline().
  * Returns the line read from STREAM in *STRINGBUF, and indicates
  * end-of-file in *EOF.  If DETECT_EOL is TRUE, the end-of-line indicator
@@ -286,7 +281,7 @@ stream_readline_bytewise(svn_stringbuf_t
      optimize for the 90% case.  90% of the time, we can avoid the
      stringbuf ever having to realloc() itself if we start it out at
      80 chars.  */
-  str = svn_stringbuf_create_ensure(LINE_CHUNK_SIZE, pool);
+  str = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool);
 
   /* Read into STR up to and including the next EOL sequence. */
   match = eol;
@@ -330,7 +325,7 @@ stream_readline_chunky(svn_stringbuf_t *
    * larger value because filling the buffer from the stream takes
    * time as well.
    */
-  char buffer[LINE_CHUNK_SIZE+1];
+  char buffer[SVN__LINE_CHUNK_SIZE+1];
 
   /* variables */
   svn_stream_mark_t *mark;
@@ -347,7 +342,7 @@ stream_readline_chunky(svn_stringbuf_t *
   SVN_ERR(svn_stream_mark(stream, &mark, pool));
 
   /* Read the first chunk. */
-  numbytes = LINE_CHUNK_SIZE;
+  numbytes = SVN__LINE_CHUNK_SIZE;
   SVN_ERR(svn_stream_read(stream, buffer, &numbytes));
   buffer[numbytes] = '\0';
 
@@ -359,7 +354,7 @@ stream_readline_chunky(svn_stringbuf_t *
       *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
       total_parsed = eol_pos - buffer + eol_len;
     }
-  else if (numbytes < LINE_CHUNK_SIZE)
+  else if (numbytes < SVN__LINE_CHUNK_SIZE)
     {
       /* We hit EOF but not EOL.
        */
@@ -371,7 +366,7 @@ stream_readline_chunky(svn_stringbuf_t *
     {
       /* A larger buffer for the string is needed. */
       svn_stringbuf_t *str;
-      str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool);
+      str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool);
       svn_stringbuf_appendbytes(str, buffer, numbytes);
       *stringbuf = str;
 
@@ -381,8 +376,8 @@ stream_readline_chunky(svn_stringbuf_t *
       {
         /* Append the next chunk to the string read so far.
          */
-        svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE);
-        numbytes = LINE_CHUNK_SIZE;
+        svn_stringbuf_ensure(str, str->len + SVN__LINE_CHUNK_SIZE);
+        numbytes = SVN__LINE_CHUNK_SIZE;
         SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes));
         str->len += numbytes;
         str->data[str->len] = '\0';
@@ -393,7 +388,7 @@ stream_readline_chunky(svn_stringbuf_t *
          */
         eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
 
-        if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL))
+        if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL))
         {
           /* We hit EOF instead of EOL. */
           *eof = TRUE;

Modified: subversion/branches/fsfs-improvements/subversion/svn/mergeinfo-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/svn/mergeinfo-cmd.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/svn/mergeinfo-cmd.c (original)
+++ subversion/branches/fsfs-improvements/subversion/svn/mergeinfo-cmd.c Sun Dec  1 18:51:26 2013
@@ -275,7 +275,8 @@ mergeinfo_summary(
 
   target_is_wc = (! svn_path_is_url(target_path_or_url))
                  && (target_revision->kind == svn_opt_revision_unspecified
-                     || target_revision->kind == svn_opt_revision_working);
+                     || target_revision->kind == svn_opt_revision_working 
+                     || target_revision->kind == svn_opt_revision_base);
   SVN_ERR(svn_client_get_merging_summary(
             &is_reintegration,
             &yca_url, &yca_rev,

Modified: subversion/branches/fsfs-improvements/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/svnadmin/svnadmin.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/fsfs-improvements/subversion/svnadmin/svnadmin.c Sun Dec  1 18:51:26 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));
+                             &notify_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);
+                           &notify_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(&notify_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, &notify_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, &notify_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));
+                       &notify_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,79 @@ 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,
+                                    &notify_baton, check_cancel,
+                                    NULL, pool);
+
+  /* Show the --keep-going error summary. */
+  if (opt_state->keep_going && notify_baton.error_summary->nelts > 0)
+    {
+      int rev_maxlength;
+      svn_revnum_t end_revnum;
+      apr_pool_t *iterpool;
+      int i;
+
+      svn_error_clear(
+        svn_stream_puts(notify_baton.feedback_stream,
+                          _("\n-----Summary of corrupt revisions-----\n")));
+
+      /* The standard column width for the revision number is 6 characters.
+         If the revision number can potentially be larger (i.e. if end_revnum
+         is larger than 1000000), we increase the column width as needed. */
+      rev_maxlength = 6;
+      end_revnum = APR_ARRAY_IDX(notify_baton.error_summary,
+                                 notify_baton.error_summary->nelts - 1,
+                                 struct verification_error *)->rev;
+      while (end_revnum >= 1000000)
+        {
+          rev_maxlength++;
+          end_revnum = end_revnum / 10;
+        }
+
+      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);
+          rev_str = apr_psprintf(iterpool, "%*s", rev_maxlength, rev_str);
+          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,
+                                                "%s: 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 +2200,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(&notify_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, &notify_baton, pool);
   if (err)
     {
       if (APR_STATUS_IS_EAGAIN(err->apr_err))
@@ -2120,7 +2229,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, &notify_baton,
                                      pool));
         }
       else if (err->apr_err == SVN_ERR_FS_UNSUPPORTED_UPGRADE)

Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/mergeinfo_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/mergeinfo_tests.py?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/mergeinfo_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/mergeinfo_tests.py Sun Dec  1 18:51:26 2013
@@ -803,6 +803,20 @@ def mergeinfo_log(sbox):
                                      '--log', sbox.repo_url + '/A',
                                      sbox.ospath('A2'))
 
+@SkipUnless(server_has_mergeinfo)
+@Issue(4301)
+def mergeinfo_local_move(sbox):
+  "'mergeinfo' on a locally moved path"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_move('A', 'A2')
+  svntest.actions.run_and_verify_svn(None,
+                                     None, [],
+                                     'mergeinfo', sbox.repo_url + '/A',
+                                     sbox.ospath('A2'))
+
 
 ########################################################################
 # Run the tests
@@ -822,6 +836,7 @@ test_list = [ None,
               natural_history_is_not_eligible_nor_merged,
               noninheritable_mergeinfo_not_always_eligible,
               mergeinfo_log,
+              mergeinfo_local_move,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py Sun Dec  1 18:51:26 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
@@ -2075,18 +2101,22 @@ def verify_denormalized_names(sbox):
     "WARNING 0x0006: Duplicate representation of path '/Q/.*lpha'"
                                   # A/{Eacute}
     " in svn:mergeinfo property of 'A/.*'",
-    ".*Verified revision 6."]
+    ".*Verified revision 6.",
+    ".*Verified revision 7."]
 
   # The BDB backend doesn't do global metadata verification.
   if not svntest.main.is_fs_type_bdb():
     expected_output_regex_list.insert(0, ".*Verifying repository metadata")
 
+    if svntest.main.is_fs_log_addressing():
+      expected_output_regex_list.insert(0, ".* Verifying metadata at revision 0 ...")
+
   exp_out = svntest.verify.RegexListOutput(expected_output_regex_list)
+  exp_err = svntest.verify.ExpectedOutput([])
 
-  if svntest.verify.verify_outputs(
-      "Unexpected error while running 'svnadmin verify'.",
-      output, errput, exp_out, None):
-    raise svntest.Failure
+  svntest.verify.verify_outputs(
+    "Unexpected error while running 'svnadmin verify'.",
+    output, errput, exp_out, exp_err)
 
 
 ########################################################################

Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests_data/normalization_check.dump
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests_data/normalization_check.dump?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests_data/normalization_check.dump [UTF-8] (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests_data/normalization_check.dump [UTF-8] Sun Dec  1 18:51:26 2013
@@ -225,3 +225,35 @@ V 26
 PROPS-END
 
 
+Revision-number: 7
+Prop-content-length: 130
+Content-length: 130
+
+K 10
+svn:author
+V 7
+jrandom
+K 8
+svn:date
+V 27
+2013-11-24T18:04:51.128158Z
+K 7
+svn:log
+V 25
+Update mergeinfo on A/É
+PROPS-END
+
+Node-path: A/É
+Node-kind: dir
+Node-action: change
+Prop-content-length: 64
+Content-length: 64
+
+K 13
+svn:mergeinfo
+V 29
+/Q/ålpha:71
+/Q/ålpha:69,71
+PROPS-END
+
+

Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py Sun Dec  1 18:51:26 2013
@@ -1336,6 +1336,9 @@ def is_fs_type_fsx():
 def is_fs_type_bdb():
   return options.fs_type == 'bdb'
 
+def is_fs_log_addressing():
+  return is_fs_type_fsx()
+
 def is_os_windows():
   return os.name == 'nt'
 

Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c Sun Dec  1 18:51:26 2013
@@ -38,6 +38,7 @@
 #include "svn_props.h"
 #include "svn_version.h"
 
+#include "private/svn_fs_util.h"
 #include "private/svn_fs_private.h"
 
 #include "../svn_test_fs.h"
@@ -5074,6 +5075,130 @@ test_fs_info_format(const svn_test_opts_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+commit_timestamp(const svn_test_opts_t *opts,
+                 apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_string_t *date = svn_string_create("Yesterday", pool);
+  svn_revnum_t rev = 0;
+  apr_hash_t *proplist;
+  svn_string_t *svn_date;
+
+  SVN_ERR(svn_test__create_fs(&fs, "test-commit-timestamp",
+                              opts, pool));
+
+  /* Commit with a specified svn:date. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/foo", pool));
+  SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_DATE, date, pool));
+  SVN_ERR(svn_fs_commit_txn2(NULL, &rev, txn, FALSE, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(svn_date && !strcmp(svn_date->data, date->data));
+
+  /* Commit that overwrites the specified svn:date. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/bar", pool));
+  SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_DATE, date, pool));
+  SVN_ERR(svn_fs_commit_txn2(NULL, &rev, txn, TRUE, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(svn_date && strcmp(svn_date->data, date->data));
+
+  /* Commit with a missing svn:date. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/zag", pool));
+  SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_DATE, NULL, pool));
+  SVN_ERR(svn_fs_txn_prop(&svn_date, txn, SVN_PROP_REVISION_DATE, pool));
+  SVN_TEST_ASSERT(!svn_date);
+  SVN_ERR(svn_fs_commit_txn2(NULL, &rev, txn, FALSE, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(!svn_date);
+
+  /* Commit that overwites a missing svn:date. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/zig", pool));
+  SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_DATE, NULL, pool));
+  SVN_ERR(svn_fs_txn_prop(&svn_date, txn, SVN_PROP_REVISION_DATE, pool));
+  SVN_TEST_ASSERT(!svn_date);
+  SVN_ERR(svn_fs_commit_txn2(NULL, &rev, txn, TRUE, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(svn_date);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_compat_version(const svn_test_opts_t *opts,
+                    apr_pool_t *pool)
+{
+  svn_version_t *compatible_version;
+  apr_hash_t *config = apr_hash_make(pool);
+  
+  svn_version_t vcurrent = {SVN_VER_MAJOR, SVN_VER_MINOR, 0, ""};
+  svn_version_t v1_2_0 = {1, 2, 0, ""};
+  svn_version_t v1_3_0 = {1, 3, 0, ""};
+  svn_version_t v1_5_0 = {1, 5, 0, ""};
+
+  /* no version specified -> default to the current one */
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &vcurrent));
+
+  /* test specific compat option */
+  svn_hash_sets(config, SVN_FS_CONFIG_PRE_1_6_COMPATIBLE, "1");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_5_0));
+
+  /* test precedence amongst compat options */
+  svn_hash_sets(config, SVN_FS_CONFIG_PRE_1_8_COMPATIBLE, "1");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_5_0));
+
+  svn_hash_sets(config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE, "1");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_3_0));
+
+  /* precedence should work with the generic option as well */
+  svn_hash_sets(config, SVN_FS_CONFIG_COMPATIBLE_VERSION, "1.4.17-??");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_3_0));
+
+  svn_hash_sets(config, SVN_FS_CONFIG_COMPATIBLE_VERSION, "1.2.3-no!");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_2_0));
+
+  /* test generic option alone */
+  config = apr_hash_make(pool);
+  svn_hash_sets(config, SVN_FS_CONFIG_COMPATIBLE_VERSION, "1.2.3-no!");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &v1_2_0));
+
+  /* out of range values should be caped by the current tool version */
+  svn_hash_sets(config, SVN_FS_CONFIG_COMPATIBLE_VERSION, "2.3.4-x");
+  SVN_ERR(svn_fs__compatible_version(&compatible_version, config, pool));
+  SVN_TEST_ASSERT(svn_ver_equal(compatible_version, &vcurrent));
+
+  return SVN_NO_ERROR;
+}
+
+
 /* ------------------------------------------------------------------------ */
 
 /* The test table.  */
@@ -5162,5 +5287,9 @@ struct svn_test_descriptor_t test_funcs[
                        "filenames with trailing \\n might be rejected"),
     SVN_TEST_OPTS_PASS(test_fs_info_format,
                        "test svn_fs_info_format"),
+    SVN_TEST_OPTS_PASS(commit_timestamp,
+                       "commit timestamp"),
+    SVN_TEST_OPTS_PASS(test_compat_version,
+                       "test svn_fs__compatible_version"),
     SVN_TEST_NULL
   };

Propchange: subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/tests/libsvn_fs_x:r1545955-1546835
  Merged /subversion/branches/verify-keep-going/subversion/tests/libsvn_fs_x:r1546002-1546110

Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_subr/checksum-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_subr/checksum-test.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_subr/checksum-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_subr/checksum-test.c Sun Dec  1 18:51:26 2013
@@ -31,34 +31,44 @@
 
 #include "../svn_test.h"
 
+/* Verify that DIGEST of checksum type KIND can be parsed and
+ * converted back to a string matching DIGEST.  NAME will be used
+ * to identify the type of checksum in error messages.
+ */
 static svn_error_t *
-test_checksum_parse(apr_pool_t *pool)
+checksum_parse_kind(const char *digest,
+                    svn_checksum_kind_t kind,
+                    const char *name,
+                    apr_pool_t *pool)
 {
-  const char *md5_digest = "8518b76f7a45fe4de2d0955085b41f98";
-  const char *sha1_digest = "74d82379bcc6771454377db03b912c2b62704139";
   const char *checksum_display;
   svn_checksum_t *checksum;
 
-  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, md5_digest, pool));
+  SVN_ERR(svn_checksum_parse_hex(&checksum, kind, digest, pool));
   checksum_display = svn_checksum_to_cstring_display(checksum, pool);
 
-  if (strcmp(checksum_display, md5_digest) != 0)
+  if (strcmp(checksum_display, digest) != 0)
     return svn_error_createf
       (SVN_ERR_CHECKSUM_MISMATCH, NULL,
-       "verify-checksum: md5 checksum mismatch:\n"
+       "verify-checksum: %s checksum mismatch:\n"
        "   expected:  %s\n"
-       "     actual:  %s\n", md5_digest, checksum_display);
+       "     actual:  %s\n", name, digest, checksum_display);
 
-  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, sha1_digest,
-                                 pool));
-  checksum_display = svn_checksum_to_cstring_display(checksum, pool);
+  return SVN_NO_ERROR;
+}
 
-  if (strcmp(checksum_display, sha1_digest) != 0)
-    return svn_error_createf
-      (SVN_ERR_CHECKSUM_MISMATCH, NULL,
-       "verify-checksum: sha1 checksum mismatch:\n"
-       "   expected:  %s\n"
-       "     actual:  %s\n", sha1_digest, checksum_display);
+static svn_error_t *
+test_checksum_parse(apr_pool_t *pool)
+{
+  SVN_ERR(checksum_parse_kind("8518b76f7a45fe4de2d0955085b41f98",
+                              svn_checksum_md5, "md5", pool));
+  SVN_ERR(checksum_parse_kind("74d82379bcc6771454377db03b912c2b62704139",
+                              svn_checksum_sha1, "sha1", pool));
+  SVN_ERR(checksum_parse_kind("deadbeef",
+                              svn_checksum_fnv1a_32, "fnv-1a", pool));
+  SVN_ERR(checksum_parse_kind("cafeaffe",
+                              svn_checksum_fnv1a_32x4,
+                              "modified fnv-1a", pool));
 
   return SVN_NO_ERROR;
 }
@@ -66,20 +76,18 @@ test_checksum_parse(apr_pool_t *pool)
 static svn_error_t *
 test_checksum_empty(apr_pool_t *pool)
 {
-  svn_checksum_t *checksum;
-  char data = '\0';
-
-  checksum = svn_checksum_empty_checksum(svn_checksum_md5, pool);
-  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
-
-  checksum = svn_checksum_empty_checksum(svn_checksum_sha1, pool);
-  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+  svn_checksum_kind_t kind;
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    {
+      svn_checksum_t *checksum;
+      char data = '\0';
 
-  SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, &data, 0, pool));
-  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+      checksum = svn_checksum_empty_checksum(kind, pool);
+      SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
 
-  SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, &data, 0, pool));
-  SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+      SVN_ERR(svn_checksum(&checksum, kind, &data, 0, pool));
+      SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -116,44 +124,81 @@ test_pseudo_md5(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+/* Verify that "zero" checksums work properly for the given checksum KIND.
+ */
 static svn_error_t *
-zero_match(apr_pool_t *pool)
+zero_match_kind(svn_checksum_kind_t kind, apr_pool_t *pool)
 {
-  svn_checksum_t *zero_md5;
-  svn_checksum_t *zero_sha1;
-  svn_checksum_t *A_md5;
-  svn_checksum_t *B_md5;
-  svn_checksum_t *A_sha1;
-  svn_checksum_t *B_sha1;
-
-
-  zero_md5 = svn_checksum_create(svn_checksum_md5, pool);
-  SVN_ERR(svn_checksum_clear(zero_md5));
-  SVN_ERR(svn_checksum(&A_md5, svn_checksum_md5, "A", 1, pool));
-  SVN_ERR(svn_checksum(&B_md5, svn_checksum_md5, "B", 1, pool));
-
-  zero_sha1 = svn_checksum_create(svn_checksum_sha1, pool);
-  SVN_ERR(svn_checksum_clear(zero_sha1));
-  SVN_ERR(svn_checksum(&A_sha1, svn_checksum_sha1, "A", 1, pool));
-  SVN_ERR(svn_checksum(&B_sha1, svn_checksum_sha1, "B", 1, pool));
+  svn_checksum_t *zero;
+  svn_checksum_t *A;
+  svn_checksum_t *B;
+
+  zero = svn_checksum_create(kind, pool);
+  SVN_ERR(svn_checksum_clear(zero));
+  SVN_ERR(svn_checksum(&A, kind, "A", 1, pool));
+  SVN_ERR(svn_checksum(&B, kind, "B", 1, pool));
 
   /* Different non-zero don't match. */
-  SVN_TEST_ASSERT(!svn_checksum_match(A_md5, B_md5));
-  SVN_TEST_ASSERT(!svn_checksum_match(A_sha1, B_sha1));
-  SVN_TEST_ASSERT(!svn_checksum_match(A_md5, A_sha1));
-  SVN_TEST_ASSERT(!svn_checksum_match(A_md5, B_sha1));
+  SVN_TEST_ASSERT(!svn_checksum_match(A, B));
 
   /* Zero matches anything of the same kind. */
-  SVN_TEST_ASSERT(svn_checksum_match(A_md5, zero_md5));
-  SVN_TEST_ASSERT(svn_checksum_match(zero_md5, B_md5));
-  SVN_TEST_ASSERT(svn_checksum_match(A_sha1, zero_sha1));
-  SVN_TEST_ASSERT(svn_checksum_match(zero_sha1, B_sha1));
-
-  /* Zero doesn't match anything of a different kind... */
-  SVN_TEST_ASSERT(!svn_checksum_match(zero_md5, A_sha1));
-  SVN_TEST_ASSERT(!svn_checksum_match(zero_sha1, A_md5));
-  /* ...even another zero. */
-  SVN_TEST_ASSERT(!svn_checksum_match(zero_md5, zero_sha1));
+  SVN_TEST_ASSERT(svn_checksum_match(A, zero));
+  SVN_TEST_ASSERT(svn_checksum_match(zero, B));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+zero_match(apr_pool_t *pool)
+{
+  svn_checksum_kind_t kind;
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    SVN_ERR(zero_match_kind(kind, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+zero_cross_match(apr_pool_t *pool)
+{
+  svn_checksum_kind_t i_kind;
+  svn_checksum_kind_t k_kind;
+
+  for (i_kind = svn_checksum_md5;
+       i_kind <= svn_checksum_fnv1a_32x4;
+       ++i_kind)
+    {
+      svn_checksum_t *i_zero;
+      svn_checksum_t *i_A;
+    
+      i_zero = svn_checksum_create(i_kind, pool);
+      SVN_ERR(svn_checksum_clear(i_zero));
+      SVN_ERR(svn_checksum(&i_A, i_kind, "A", 1, pool));
+
+      for (k_kind = svn_checksum_md5;
+           k_kind <= svn_checksum_fnv1a_32x4;
+           ++k_kind)
+        {
+          svn_checksum_t *k_zero;
+          svn_checksum_t *k_A;
+          if (i_kind == k_kind)
+            continue;
+
+          k_zero = svn_checksum_create(k_kind, pool);
+          SVN_ERR(svn_checksum_clear(k_zero));
+          SVN_ERR(svn_checksum(&k_A, k_kind, "A", 1, pool));
+
+          /* Different non-zero don't match. */
+          SVN_TEST_ASSERT(!svn_checksum_match(i_A, k_A));
+
+          /* Zero doesn't match anything of a different kind... */
+          SVN_TEST_ASSERT(!svn_checksum_match(i_zero, k_A));
+          SVN_TEST_ASSERT(!svn_checksum_match(i_A, k_zero));
+
+          /* ...even another zero. */
+          SVN_TEST_ASSERT(!svn_checksum_match(i_zero, k_zero));
+        }
+    }
 
   return SVN_NO_ERROR;
 }
@@ -256,5 +301,7 @@ struct svn_test_descriptor_t test_funcs[
                    "zero checksum matching"),
     SVN_TEST_OPTS_PASS(zlib_expansion_test,
                        "zlib expansion test (zlib regression)"),
+    SVN_TEST_PASS2(zero_cross_match,
+                   "zero checksum cross-type matching"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/fsfs-improvements/subversion/tests/svn_test_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/svn_test_fs.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/svn_test_fs.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/svn_test_fs.c Sun Dec  1 18:51:26 2013
@@ -83,6 +83,8 @@ make_fs_config(const char *fs_type,
                fs_type);
   if (server_minor_version)
     {
+      svn_hash_sets(fs_config, SVN_FS_CONFIG_COMPATIBLE_VERSION,
+                    apr_psprintf(pool, "1.%d.0", server_minor_version));
       if (server_minor_version == 6 || server_minor_version == 7)
         svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_8_COMPATIBLE, "1");
       else if (server_minor_version == 5)

Modified: subversion/branches/fsfs-improvements/subversion/tests/svn_test_main.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/svn_test_main.c?rev=1546837&r1=1546836&r2=1546837&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/svn_test_main.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/svn_test_main.c Sun Dec  1 18:51:26 2013
@@ -52,11 +52,8 @@
 
 #include "svn_private_config.h"
 
-#if APR_HAS_THREADS && APR_VERSION_AT_LEAST(1,3,0)
-#  include <apr_thread_pool.h>
-#  define HAVE_THREADPOOLS 1
-#else
-#  define HAVE_THREADPOOLS 0
+#if APR_HAS_THREADS
+#  include <apr_thread_proc.h>
 #endif
 
 /* Some Subversion test programs may want to parse options in the
@@ -420,7 +417,7 @@ do_test_num(const char *progname,
   return skip_cleanup;
 }
 
-#if HAVE_THREADPOOLS
+#if APR_HAS_THREADS
 
 /* Per-test parameters used by test_thread */
 typedef struct test_params_t
@@ -428,67 +425,86 @@ typedef struct test_params_t
   /* Name of the application */
   const char *progname;
 
-  /* Number / index of the test to execute */
-  int test_num;
+  /* Total number of tests to execute */
+  svn_atomic_t test_count;
 
   /* Global test options as provided by main() */
   svn_test_opts_t *opts;
 
-  /* Thread-safe parent pool for the test-specific pool.  We expect the
-     test thread to create a sub-pool and destroy it after test completion. */
-  apr_pool_t *pool;
-
   /* Reference to the global failure flag.  Set this if any test failed. */
-  svn_atomic_t *got_error;
+  svn_atomic_t got_error;
 
-  /* Reference to the global completed test counter. */
-  svn_atomic_t *run_count;
+  /* Test to execute next. */
+  svn_atomic_t test_num;
 } test_params_t;
 
 /* Thread function similar to do_test_num() but with fewer options.  We do
    catch segfaults.  All parameters are given as a test_params_t in DATA.
  */
 static void * APR_THREAD_FUNC
-test_thread(apr_thread_t *tid, void *data)
+test_thread(apr_thread_t *thread, void *data)
 {
   svn_boolean_t skip, xfail, wimp;
   svn_error_t *err = NULL;
   const struct svn_test_descriptor_t *desc;
   svn_boolean_t run_this_test; /* This test's mode matches DESC->MODE. */
   test_params_t *params = data;
+  svn_atomic_t test_num;
 
-  apr_pool_t *test_pool = svn_pool_create(params->pool);
+  apr_pool_t *pool
+    = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
 
-  desc = &test_funcs[params->test_num];
-  skip = desc->mode == svn_test_skip;
-  xfail = desc->mode == svn_test_xfail;
-  wimp = xfail && desc->wip;
-  run_this_test = mode_filter == svn_test_all || mode_filter == desc->mode;
+  for (test_num = svn_atomic_inc(&params->test_num);
+       test_num <= params->test_count;
+       test_num = svn_atomic_inc(&params->test_num))
+    {
+      svn_pool_clear(pool);
+
+      desc = &test_funcs[test_num];
+      skip = desc->mode == svn_test_skip;
+      xfail = desc->mode == svn_test_xfail;
+      wimp = xfail && desc->wip;
+      run_this_test = mode_filter == svn_test_all
+                   || mode_filter == desc->mode;
 
-  /* Do test */
-  if (skip || !run_this_test)
-    ; /* pass */
-  else if (desc->func2)
-    err = (*desc->func2)(test_pool);
-  else
-    err = (*desc->func_opts)(params->opts, test_pool);
+      /* Do test */
+      if (skip || !run_this_test)
+        ; /* pass */
+      else if (desc->func2)
+        err = (*desc->func2)(pool);
+      else
+        err = (*desc->func_opts)(params->opts, pool);
 
-  /* Write results to console */
-  svn_error_clear(svn_mutex__lock(log_mutex));
-  if (log_results(params->progname, params->test_num, FALSE, run_this_test,
-                  skip, xfail, wimp, err, desc->msg, desc))
-    svn_atomic_set(params->got_error, TRUE);
-  svn_error_clear(svn_mutex__unlock(log_mutex, NULL));
+      /* Write results to console */
+      svn_error_clear(svn_mutex__lock(log_mutex));
+      if (log_results(params->progname, test_num, FALSE, run_this_test,
+                      skip, xfail, wimp, err, desc->msg, desc))
+        svn_atomic_set(&params->got_error, TRUE);
+      svn_error_clear(svn_mutex__unlock(log_mutex, NULL));
+    }
 
   /* release all test memory */
-  svn_pool_destroy(test_pool);
+  svn_pool_destroy(pool);
 
-  /* one more test completed */
-  svn_atomic_inc(params->run_count);
-    
+  /* End thread explicitly to prevent APR_INCOMPLETE return codes in
+     apr_thread_join(). */
+  apr_thread_exit(thread, 0);
   return NULL;
 }
 
+/* Log an error with message MSG if the APR status of EXPR is not 0.
+ */
+#define CHECK_STATUS(expr,msg) \
+  do { \
+    apr_status_t rv = (expr); \
+    if (rv) \
+      { \
+        svn_error_t *svn_err__temp = svn_error_wrap_apr(rv, msg); \
+        svn_handle_error2(svn_err__temp, stdout, FALSE, "svn_tests: "); \
+        svn_error_clear(svn_err__temp); \
+      } \
+  } while (0);
+
 /* Execute all ARRAY_SIZE tests concurrently using MAX_THREADS threads.
    Pass PROGNAME and OPTS to the individual tests.  Return TRUE if at least
    one of the tests failed.  Allocate all data in POOL.
@@ -502,56 +518,37 @@ do_tests_concurrently(const char *progna
                       svn_test_opts_t *opts,
                       apr_pool_t *pool)
 {
-  apr_thread_pool_t *threads;
-  apr_status_t status;
-  svn_atomic_t got_error = FALSE;
   int i;
-  svn_atomic_t run_count = 0;
-
-  /* Create the thread pool. */
-  status = apr_thread_pool_create(&threads, max_threads, max_threads, pool);
-  if (status)
-    {
-      printf("apr_thread_pool_create() failed.\n");
-      return TRUE;
-    }
-
-  /* Don't queue requests unless we reached the worker thread limit. */
-  apr_thread_pool_threshold_set(threads, 0);
-
-  /* Generate one task per test and queue them in the thread pool. */
-  for (i = 1; i <= array_size; i++)
-    {
-      test_params_t *params = apr_pcalloc(pool, sizeof(*params));
-      params->got_error = &got_error;
-      params->opts = opts;
-      params->pool = pool;
-      params->progname = progname;
-      params->test_num = i;
-      params->run_count = &run_count;
+  apr_thread_t **threads;
 
-      apr_thread_pool_push(threads, test_thread, params, 0, NULL);
+  /* Prepare thread parameters. */
+  test_params_t params;
+  params.got_error = FALSE;
+  params.opts = opts;
+  params.progname = progname;
+  params.test_num = 1;
+  params.test_count = array_size;
+
+  /* Start all threads. */
+  threads = apr_pcalloc(pool, max_threads * sizeof(*threads));
+  for (i = 0; i < max_threads; ++i)
+    {
+      CHECK_STATUS(apr_thread_create(&threads[i], NULL, test_thread, &params,
+                                     pool),
+                   "creating test thread failed.\n");
+    }
+
+  /* Wait for all tasks (tests) to complete. */
+  for (i = 0; i < max_threads; ++i)
+    {
+      apr_status_t result = 0;
+      CHECK_STATUS(apr_thread_join(&result, threads[i]),
+                   "Waiting for test thread to finish failed.");
+      CHECK_STATUS(result,
+                   "Test thread returned an error.");
     }
-
-  /* Wait for all tasks (tests) to complete.  As it turns out, this is the
-     variant with the least run-time overhead to the test threads. */
-  while (   apr_thread_pool_tasks_count(threads)
-         || apr_thread_pool_busy_count(threads))
-    apr_thread_yield();
   
-  /* For some unknown reason, cleaning POOL (TEST_POOL in main()) does not
-     call the following reliably for all users. */
-  apr_thread_pool_destroy(threads);
-
-  /* Verify that we didn't skip any tasks. */
-  if (run_count != array_size)
-    {
-      printf("Parallel test failure: only %d of %d tests executed.\n",
-             (int)run_count, array_size);
-      return TRUE;
-    }
-
-  return got_error != FALSE;
+  return params.got_error != FALSE;
 }
 
 #endif
@@ -798,7 +795,7 @@ main(int argc, const char *argv[])
               }
             break;
           }
-#if HAVE_THREADPOOLS
+#if APR_HAS_THREADS
         case parallel_opt:
           parallel = TRUE;
           break;
@@ -888,7 +885,7 @@ main(int argc, const char *argv[])
               svn_pool_clear(cleanup_pool);
             }
         }
-#if HAVE_THREADPOOLS
+#if APR_HAS_THREADS
       else
         {
           got_error = do_tests_concurrently(prog_name, array_size,



Mime
View raw message