You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [30/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/dump.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/dump.c Mon Nov 30 10:24:16 2015
@@ -1164,13 +1164,13 @@ dump_node(struct edit_baton *eb,
                                    svn_fs_root_fs(eb->fs_root),
                                    compare_rev, pool));
 
-      SVN_ERR(svn_fs_props_different(&must_dump_props,
-                                     compare_root, compare_path,
-                                     eb->fs_root, path, pool));
+      SVN_ERR(svn_fs_props_changed(&must_dump_props,
+                                   compare_root, compare_path,
+                                   eb->fs_root, path, pool));
       if (kind == svn_node_file)
-        SVN_ERR(svn_fs_contents_different(&must_dump_text,
-                                          compare_root, compare_path,
-                                          eb->fs_root, path, pool));
+        SVN_ERR(svn_fs_contents_changed(&must_dump_text,
+                                        compare_root, compare_path,
+                                        eb->fs_root, path, pool));
       break;
 
     case svn_node_action_delete:
@@ -1293,16 +1293,16 @@ dump_node(struct edit_baton *eb,
 
           /* Need to decide if the copied node had any extra textual or
              property mods as well.  */
-          SVN_ERR(svn_fs_props_different(&must_dump_props,
-                                         compare_root, compare_path,
-                                         eb->fs_root, path, pool));
+          SVN_ERR(svn_fs_props_changed(&must_dump_props,
+                                       compare_root, compare_path,
+                                       eb->fs_root, path, pool));
           if (kind == svn_node_file)
             {
               svn_checksum_t *checksum;
               const char *hex_digest;
-              SVN_ERR(svn_fs_contents_different(&must_dump_text,
-                                                compare_root, compare_path,
-                                                eb->fs_root, path, pool));
+              SVN_ERR(svn_fs_contents_changed(&must_dump_text,
+                                              compare_root, compare_path,
+                                              eb->fs_root, path, pool));
 
               SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                            compare_root, compare_path,
@@ -1919,33 +1919,44 @@ get_dump_editor(const svn_delta_editor_t
 /* Helper for svn_repos_dump_fs.
 
    Write a revision record of REV in FS to writable STREAM, using POOL.
+   Dump revision properties as well if INCLUDE_REVPROPS has been set.
  */
 static svn_error_t *
 write_revision_record(svn_stream_t *stream,
                       svn_fs_t *fs,
                       svn_revnum_t rev,
+                      svn_boolean_t include_revprops,
                       apr_pool_t *pool)
 {
   apr_hash_t *props;
   apr_time_t timetemp;
   svn_string_t *datevalue;
 
-  SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool));
+  if (include_revprops)
+    {
+      SVN_ERR(svn_fs_revision_proplist2(&props, fs, rev, FALSE, pool, pool));
 
-  /* Run revision date properties through the time conversion to
-     canonicalize them. */
-  /* ### Remove this when it is no longer needed for sure. */
-  datevalue = svn_hash_gets(props, SVN_PROP_REVISION_DATE);
-  if (datevalue)
-    {
-      SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool));
-      datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool),
-                                    pool);
-      svn_hash_sets(props, SVN_PROP_REVISION_DATE, datevalue);
+      /* Run revision date properties through the time conversion to
+        canonicalize them. */
+      /* ### Remove this when it is no longer needed for sure. */
+      datevalue = svn_hash_gets(props, SVN_PROP_REVISION_DATE);
+      if (datevalue)
+        {
+          SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool));
+          datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool),
+                                        pool);
+          svn_hash_sets(props, SVN_PROP_REVISION_DATE, datevalue);
+        }
+    }
+   else
+    {
+      /* Although we won't use it, we still need this container for the
+         call below. */
+      props = apr_hash_make(pool);
     }
 
   SVN_ERR(svn_repos__dump_revision_record(stream, rev, NULL, props,
-                                          TRUE /*props_section_always*/,
+                                          include_revprops,
                                           pool));
   return SVN_NO_ERROR;
 }
@@ -1954,12 +1965,14 @@ write_revision_record(svn_stream_t *stre
 
 /* The main dumper. */
 svn_error_t *
-svn_repos_dump_fs3(svn_repos_t *repos,
+svn_repos_dump_fs4(svn_repos_t *repos,
                    svn_stream_t *stream,
                    svn_revnum_t start_rev,
                    svn_revnum_t end_rev,
                    svn_boolean_t incremental,
                    svn_boolean_t use_deltas,
+                   svn_boolean_t include_revprops,
+                   svn_boolean_t include_changes,
                    svn_repos_notify_func_t notify_func,
                    void *notify_baton,
                    svn_cancel_func_t cancel_func,
@@ -1970,7 +1983,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
   void *dump_edit_baton = NULL;
   svn_revnum_t rev;
   svn_fs_t *fs = svn_repos_fs(repos);
-  apr_pool_t *subpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(pool);
   svn_revnum_t youngest;
   const char *uuid;
   int version;
@@ -1978,6 +1991,10 @@ svn_repos_dump_fs3(svn_repos_t *repos,
   svn_boolean_t found_old_mergeinfo = FALSE;
   svn_repos_notify_t *notify;
 
+  /* Make sure we catch up on the latest revprop changes.  This is the only
+   * time we will refresh the revprop data in this query. */
+  SVN_ERR(svn_fs_refresh_revision_props(fs, pool));
+
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
 
@@ -2029,18 +2046,20 @@ svn_repos_dump_fs3(svn_repos_t *repos,
       svn_fs_root_t *to_root;
       svn_boolean_t use_deltas_for_rev;
 
-      svn_pool_clear(subpool);
+      svn_pool_clear(iterpool);
 
       /* Check for cancellation. */
       if (cancel_func)
         SVN_ERR(cancel_func(cancel_baton));
 
       /* Write the revision record. */
-      SVN_ERR(write_revision_record(stream, fs, rev, subpool));
+      SVN_ERR(write_revision_record(stream, fs, rev, include_revprops,
+                                    iterpool));
 
       /* When dumping revision 0, we just write out the revision record.
-         The parser might want to use its properties. */
-      if (rev == 0)
+         The parser might want to use its properties.
+         If we don't want revision changes at all, skip in any case. */
+      if (rev == 0 || !include_changes)
         goto loop_end;
 
       /* Fetch the editor which dumps nodes to a file.  Regardless of
@@ -2052,10 +2071,10 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                               &found_old_mergeinfo, NULL,
                               notify_func, notify_baton,
                               start_rev, use_deltas_for_rev, FALSE, FALSE,
-                              subpool));
+                              iterpool));
 
       /* Drive the editor in one way or another. */
-      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
+      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
 
       /* If this is the first revision of a non-incremental dump,
          we're in for a full tree dump.  Otherwise, we want to simply
@@ -2064,7 +2083,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
         {
           /* Compare against revision 0, so everything appears to be added. */
           svn_fs_root_t *from_root;
-          SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, subpool));
+          SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, iterpool));
           SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
                                        to_root, "",
                                        dump_editor, dump_edit_baton,
@@ -2074,25 +2093,25 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                                        svn_depth_infinity,
                                        FALSE, /* don't send entry props */
                                        FALSE, /* don't ignore ancestry */
-                                       subpool));
+                                       iterpool));
         }
       else
         {
           /* The normal case: compare consecutive revs. */
           SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                     dump_editor, dump_edit_baton,
-                                    NULL, NULL, subpool));
+                                    NULL, NULL, iterpool));
 
           /* While our editor close_edit implementation is a no-op, we still
              do this for completeness. */
-          SVN_ERR(dump_editor->close_edit(dump_edit_baton, subpool));
+          SVN_ERR(dump_editor->close_edit(dump_edit_baton, iterpool));
         }
 
     loop_end:
       if (notify_func)
         {
           notify->revision = rev;
-          notify_func(notify_baton, notify, subpool);
+          notify_func(notify_baton, notify, iterpool);
         }
     }
 
@@ -2103,12 +2122,12 @@ svn_repos_dump_fs3(svn_repos_t *repos,
          warning, since the inline warnings already issued might easily be
          missed. */
 
-      notify = svn_repos_notify_create(svn_repos_notify_dump_end, subpool);
-      notify_func(notify_baton, notify, subpool);
+      notify = svn_repos_notify_create(svn_repos_notify_dump_end, iterpool);
+      notify_func(notify_baton, notify, iterpool);
 
       if (found_old_reference)
         {
-          notify_warning(subpool, notify_func, notify_baton,
+          notify_warning(iterpool, notify_func, notify_baton,
                          svn_repos_notify_warning_found_old_reference,
                          _("The range of revisions dumped "
                            "contained references to "
@@ -2120,7 +2139,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
          in dumped mergeinfo. */
       if (found_old_mergeinfo)
         {
-          notify_warning(subpool, notify_func, notify_baton,
+          notify_warning(iterpool, notify_func, notify_baton,
                          svn_repos_notify_warning_found_old_mergeinfo,
                          _("The range of revisions dumped "
                            "contained mergeinfo "
@@ -2129,7 +2148,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
         }
     }
 
-  svn_pool_destroy(subpool);
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
@@ -2265,24 +2284,6 @@ 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)
-{
-  svn_repos_notify_t *notify_failure;
-
-  if (notify_func == NULL)
-    return;
-
-  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);
-}
-
 /* Verify revision REV in file system FS. */
 static svn_error_t *
 verify_one_revision(svn_fs_t *fs,
@@ -2328,13 +2329,14 @@ verify_one_revision(svn_fs_t *fs,
      do this for completeness. */
   SVN_ERR(cancel_editor->close_edit(cancel_edit_baton, scratch_pool));
 
-  SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, scratch_pool));
+  SVN_ERR(svn_fs_revision_proplist2(&props, fs, rev, FALSE, scratch_pool,
+                                    scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
 /* Baton type used for forwarding notifications from FS API to REPOS API. */
-struct verify_fs2_notify_func_baton_t
+struct verify_fs_notify_func_baton_t
 {
    /* notification function to call (must not be NULL) */
    svn_repos_notify_func_t notify_func;
@@ -2348,26 +2350,53 @@ struct verify_fs2_notify_func_baton_t
 
 /* Forward the notification to BATON. */
 static void
-verify_fs2_notify_func(svn_revnum_t revision,
+verify_fs_notify_func(svn_revnum_t revision,
                        void *baton,
                        apr_pool_t *pool)
 {
-  struct verify_fs2_notify_func_baton_t *notify_baton = baton;
+  struct verify_fs_notify_func_baton_t *notify_baton = baton;
 
   notify_baton->notify->revision = revision;
   notify_baton->notify_func(notify_baton->notify_baton,
                             notify_baton->notify, pool);
 }
 
+static svn_error_t *
+report_error(svn_revnum_t revision,
+             svn_error_t *verify_err,
+             svn_repos_verify_callback_t verify_callback,
+             void *verify_baton,
+             apr_pool_t *pool)
+{
+  if (verify_callback)
+    {
+      svn_error_t *cb_err;
+
+      /* The caller provided us with a callback, so make him responsible
+         for what's going to happen with the error. */
+      cb_err = verify_callback(verify_baton, revision, verify_err, pool);
+      svn_error_clear(verify_err);
+      SVN_ERR(cb_err);
+
+      return SVN_NO_ERROR;
+    }
+  else
+    {
+      /* No callback -- no second guessing.  Just return the error. */
+      return svn_error_trace(verify_err);
+    }
+}
+
 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_boolean_t check_normalization,
                      svn_boolean_t metadata_only,
                      svn_repos_notify_func_t notify_func,
                      void *notify_baton,
+                     svn_repos_verify_callback_t verify_callback,
+                     void *verify_baton,
                      svn_cancel_func_t cancel_func,
                      void *cancel_baton,
                      apr_pool_t *pool)
@@ -2378,9 +2407,12 @@ svn_repos_verify_fs3(svn_repos_t *repos,
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_repos_notify_t *notify;
   svn_fs_progress_notify_func_t verify_notify = NULL;
-  struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
+  struct verify_fs_notify_func_baton_t *verify_notify_baton = NULL;
   svn_error_t *err;
-  svn_boolean_t found_corruption = FALSE;
+
+  /* Make sure we catch up on the latest revprop changes.  This is the only
+   * time we will refresh the revprop data in this query. */
+  SVN_ERR(svn_fs_refresh_revision_props(fs, pool));
 
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -2409,7 +2441,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
     {
       notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end, pool);
 
-      verify_notify = verify_fs2_notify_func;
+      verify_notify = verify_fs_notify_func;
       verify_notify_baton = apr_palloc(pool, sizeof(*verify_notify_baton));
       verify_notify_baton->notify_func = notify_func;
       verify_notify_baton->notify_baton = notify_baton;
@@ -2423,34 +2455,14 @@ svn_repos_verify_fs3(svn_repos_t *repos,
                       verify_notify, verify_notify_baton,
                       cancel_func, cancel_baton, pool);
 
-  if (err)
+  if (err && err->apr_err == SVN_ERR_CANCELLED)
     {
-      if (err->apr_err == SVN_ERR_CANCELLED)
-        return svn_error_trace(err);
-
-      found_corruption = TRUE;
-      notify_verification_error(SVN_INVALID_REVNUM, err, notify_func,
-                                notify_baton, iterpool);
-
-      /* If we already reported the error, reset it. */
-      if (notify_func)
-        {
-          svn_error_clear(err);
-          err = NULL;
-        }
-
-      /* If we abort the verification now, combine yet unreported error
-         info with the generic one we return. */
-      if (!keep_going)
-        /* ### Jump to "We're done" and so send the final notification,
-               for consistency? */
-        return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, err,
-                                _("Repository '%s' failed to verify"),
-                                svn_dirent_local_style(svn_repos_path(repos,
-                                                                      pool),
-                                                        pool));
-
-      svn_error_clear(err);
+      return svn_error_trace(err);
+    }
+  else if (err)
+    {
+      SVN_ERR(report_error(SVN_INVALID_REVNUM, err, verify_callback,
+                           verify_baton, iterpool));
     }
 
   if (!metadata_only)
@@ -2464,24 +2476,18 @@ svn_repos_verify_fs3(svn_repos_t *repos,
                                   cancel_func, cancel_baton,
                                   iterpool);
 
-        if (err)
+        if (err && err->apr_err == SVN_ERR_CANCELLED)
           {
-            if (err->apr_err == SVN_ERR_CANCELLED)
-              return svn_error_trace(err);
-
-            found_corruption = TRUE;
-            notify_verification_error(rev, err, notify_func, notify_baton,
-                                      iterpool);
-            svn_error_clear(err);
-
-            if (keep_going)
-              continue;
-            else
-              break;
+            return svn_error_trace(err);
           }
-
-        if (notify_func)
+        else if (err)
           {
+            SVN_ERR(report_error(rev, err, verify_callback, verify_baton,
+                                 iterpool));
+          }
+        else if (notify_func)
+          {
+            /* Tell the caller that we're done with this revision. */
             notify->revision = rev;
             notify_func(notify_baton, notify, iterpool);
           }
@@ -2496,12 +2502,5 @@ svn_repos_verify_fs3(svn_repos_t *repos,
 
   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;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/fs-wrap.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/fs-wrap.c Mon Nov 30 10:24:16 2015
@@ -58,6 +58,8 @@ svn_repos_fs_commit_txn(const char **con
   apr_hash_t *hooks_env;
 
   *new_rev = SVN_INVALID_REVNUM;
+  if (conflict_p)
+    *conflict_p = NULL;
 
   /* Parse the hooks-env file (if any). */
   SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
@@ -378,7 +380,8 @@ svn_repos_fs_change_rev_prop4(svn_repos_
            * to the hooks to be accurate. */
           svn_string_t *old_value2;
 
-          SVN_ERR(svn_fs_revision_prop(&old_value2, repos->fs, rev, name, pool));
+          SVN_ERR(svn_fs_revision_prop2(&old_value2, repos->fs, rev, name,
+                                        TRUE, pool, pool));
           old_value = old_value2;
         }
 
@@ -448,12 +451,13 @@ svn_repos_fs_revision_prop(svn_string_t
         *value_p = NULL;
 
       else
-        SVN_ERR(svn_fs_revision_prop(value_p, repos->fs,
-                                     rev, propname, pool));
+        SVN_ERR(svn_fs_revision_prop2(value_p, repos->fs,
+                                      rev, propname, TRUE, pool, pool));
     }
   else /* wholly readable revision */
     {
-      SVN_ERR(svn_fs_revision_prop(value_p, repos->fs, rev, propname, pool));
+      SVN_ERR(svn_fs_revision_prop2(value_p, repos->fs, rev, propname, TRUE,
+                                    pool, pool));
     }
 
   return SVN_NO_ERROR;
@@ -486,7 +490,8 @@ svn_repos_fs_revision_proplist(apr_hash_
       svn_string_t *value;
 
       /* Produce two property hashtables, both in POOL. */
-      SVN_ERR(svn_fs_revision_proplist(&tmphash, repos->fs, rev, pool));
+      SVN_ERR(svn_fs_revision_proplist2(&tmphash, repos->fs, rev, TRUE,
+                                        pool, pool));
       *table_p = apr_hash_make(pool);
 
       /* If they exist, we only copy svn:author and svn:date into the
@@ -501,7 +506,8 @@ svn_repos_fs_revision_proplist(apr_hash_
     }
   else /* wholly readable revision */
     {
-      SVN_ERR(svn_fs_revision_proplist(table_p, repos->fs, rev, pool));
+      SVN_ERR(svn_fs_revision_proplist2(table_p, repos->fs, rev, TRUE,
+                                        pool, pool));
     }
 
   return SVN_NO_ERROR;
@@ -975,15 +981,18 @@ pack_notify_func(void *baton,
 {
   struct pack_notify_baton *pnb = baton;
   svn_repos_notify_t *notify;
+  svn_repos_notify_action_t repos_action;
 
   /* Simple conversion works for these values. */
   SVN_ERR_ASSERT(pack_action >= svn_fs_pack_notify_start
-                 && pack_action <= svn_fs_pack_notify_end_revprop);
+                 && pack_action <= svn_fs_pack_notify_noop);
 
-  notify = svn_repos_notify_create(pack_action
-                                   + svn_repos_notify_pack_shard_start
-                                   - svn_fs_pack_notify_start,
-                                   pool);
+  repos_action = pack_action == svn_fs_pack_notify_noop
+               ? svn_repos_notify_pack_noop
+               : pack_action + svn_repos_notify_pack_shard_start
+                             - svn_fs_pack_notify_start;
+
+  notify = svn_repos_notify_create(repos_action, pool);
   notify->shard = shard;
   pnb->notify_func(pnb->notify_baton, notify, pool);
 

Modified: subversion/branches/ra-git/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/load-fs-vtable.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/load-fs-vtable.c Mon Nov 30 10:24:16 2015
@@ -624,14 +624,6 @@ maybe_add_with_history(struct node_baton
 }
 
 static svn_error_t *
-magic_header_record(int version,
-                    void *parse_baton,
-                    apr_pool_t *pool)
-{
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
 uuid_record(const char *uuid,
             void *parse_baton,
             apr_pool_t *pool)
@@ -1022,7 +1014,8 @@ close_revision(void *baton)
           apr_array_header_t *diff;
           int i;
 
-          SVN_ERR(svn_fs_revision_proplist(&orig_props, pb->fs, 0, rb->pool));
+          SVN_ERR(svn_fs_revision_proplist2(&orig_props, pb->fs, 0, TRUE,
+                                            rb->pool, rb->pool));
           new_props = svn_prop_array_to_hash(rb->revprops, rb->pool);
           SVN_ERR(svn_prop_diffs(&diff, new_props, orig_props, rb->pool));
 
@@ -1194,7 +1187,7 @@ svn_repos_get_fs_build_parser5(const svn
   if (SVN_IS_VALID_REVNUM(start_rev))
     SVN_ERR_ASSERT(start_rev <= end_rev);
 
-  parser->magic_header_record = magic_header_record;
+  parser->magic_header_record = NULL;
   parser->uuid_record = uuid_record;
   parser->new_revision_record = new_revision_record;
   parser->new_node_record = new_node_record;
@@ -1271,3 +1264,216 @@ svn_repos_load_fs5(svn_repos_t *repos,
   return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton, FALSE,
                                      cancel_func, cancel_baton, pool);
 }
+
+/*----------------------------------------------------------------------*/
+
+/** The same functionality for revprops only **/
+
+/* Implement svn_repos_parse_fns3_t.new_revision_record.
+ *
+ * Because the revision is supposed to already exist, we don't need to
+ * start transactions etc. */
+static svn_error_t *
+revprops_new_revision_record(void **revision_baton,
+                             apr_hash_t *headers,
+                             void *parse_baton,
+                             apr_pool_t *pool)
+{
+  struct parse_baton *pb = parse_baton;
+  struct revision_baton *rb;
+
+  rb = make_revision_baton(headers, pb, pool);
+
+  /* If we're skipping this revision, try to notify someone. */
+  if (rb->skipped && pb->notify_func)
+    {
+      /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
+      svn_repos_notify_t *notify = svn_repos_notify_create(
+                                        svn_repos_notify_load_skipped_rev,
+                                        pb->notify_pool);
+
+      notify->old_revision = rb->rev;
+      pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
+      svn_pool_clear(pb->notify_pool);
+    }
+
+  /* If we're parsing revision 0, only the revision props are (possibly)
+     interesting to us: when loading the stream into an empty
+     filesystem, then we want new filesystem's revision 0 to have the
+     same props.  Otherwise, we just ignore revision 0 in the stream. */
+
+  *revision_baton = rb;
+  return SVN_NO_ERROR;
+}
+
+/* Implement svn_repos_parse_fns3_t.close_revision.
+ *
+ * Simply set the revprops we previously parsed and send notifications.
+ * This is the place where we will detect missing revisions. */
+static svn_error_t *
+revprops_close_revision(void *baton)
+{
+  struct revision_baton *rb = baton;
+  struct parse_baton *pb = rb->pb;
+  apr_hash_t *orig_props;
+  apr_hash_t *new_props;
+  apr_array_header_t *diff;
+  int i;
+
+  /* If we're skipping this revision we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
+  /* If the dumpstream doesn't have an 'svn:date' property and we
+     aren't ignoring the dates in the dumpstream altogether, remove
+     any 'svn:date' revision property that was set by FS layer when
+     the TXN was created.  */
+  if (! (pb->ignore_dates || rb->datestamp))
+    {
+      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+      prop->name = SVN_PROP_REVISION_DATE;
+      prop->value = NULL;
+    }
+
+  SVN_ERR(svn_fs_revision_proplist2(&orig_props, pb->fs, rb->rev, TRUE,
+                                    rb->pool, rb->pool));
+  new_props = svn_prop_array_to_hash(rb->revprops, rb->pool);
+  SVN_ERR(svn_prop_diffs(&diff, new_props, orig_props, rb->pool));
+
+  for (i = 0; i < diff->nelts; i++)
+    {
+      const svn_prop_t *prop = &APR_ARRAY_IDX(diff, i, svn_prop_t);
+
+      SVN_ERR(change_rev_prop(pb->repos, rb->rev, prop->name, prop->value,
+                              pb->validate_props, rb->pool));
+    }
+
+  if (pb->notify_func)
+    {
+      /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
+      svn_repos_notify_t *notify = svn_repos_notify_create(
+                                        svn_repos_notify_load_revprop_set,
+                                        pb->notify_pool);
+
+      notify->new_revision = rb->rev;
+      notify->old_revision = SVN_INVALID_REVNUM;
+      pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
+      svn_pool_clear(pb->notify_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Set *CALLBACKS and *PARSE_BATON to a vtable parser which commits new
+ * revisions to the fs in REPOS.  Allocate the objects in RESULT_POOL.
+ *
+ * START_REV and END_REV act as filters, the lower and upper (inclusive)
+ * range values of revisions in DUMPSTREAM which will be loaded.  Either
+ * both of these values are #SVN_INVALID_REVNUM (in  which case no
+ * revision-based filtering occurs at all), or both are valid revisions
+ * (where START_REV is older than or equivalent to END_REV).
+ * 
+ * START_REV and END_REV act as filters, the lower and upper (inclusive)
+ * range values of revisions which will
+ * be loaded.  Either both of these values are #SVN_INVALID_REVNUM (in
+ * which case no revision-based filtering occurs at all), or both are
+ * valid revisions (where START_REV is older than or equivalent to
+ * END_REV).  They refer to dump stream revision numbers rather than
+ * committed revision numbers.
+ *
+ * If VALIDATE_PROPS is set, then validate Subversion revision properties
+ * (those in the svn: namespace) against established rules for those things.
+ *
+ * If IGNORE_DATES is set, ignore any revision datestamps found in
+ * DUMPSTREAM, keeping whatever timestamps the revisions currently have.
+ */
+static svn_error_t *
+build_revprop_parser(const svn_repos_parse_fns3_t **callbacks,
+                     void **parse_baton,
+                     svn_repos_t *repos,
+                     svn_revnum_t start_rev,
+                     svn_revnum_t end_rev,
+                     svn_boolean_t validate_props,
+                     svn_boolean_t ignore_dates,
+                     svn_repos_notify_func_t notify_func,
+                     void *notify_baton,
+                     apr_pool_t *result_pool)
+{
+  svn_repos_parse_fns3_t *parser = apr_pcalloc(result_pool, sizeof(*parser));
+  struct parse_baton *pb = apr_pcalloc(result_pool, sizeof(*pb));
+
+  SVN_ERR_ASSERT((SVN_IS_VALID_REVNUM(start_rev) &&
+                  SVN_IS_VALID_REVNUM(end_rev))
+                 || ((! SVN_IS_VALID_REVNUM(start_rev)) &&
+                     (! SVN_IS_VALID_REVNUM(end_rev))));
+  if (SVN_IS_VALID_REVNUM(start_rev))
+    SVN_ERR_ASSERT(start_rev <= end_rev);
+
+  parser->magic_header_record = NULL;
+  parser->uuid_record = uuid_record;
+  parser->new_revision_record = revprops_new_revision_record;
+  parser->new_node_record = NULL;
+  parser->set_revision_property = set_revision_property;
+  parser->set_node_property = NULL;
+  parser->remove_node_props = NULL;
+  parser->set_fulltext = NULL;
+  parser->close_node = NULL;
+  parser->close_revision = revprops_close_revision;
+  parser->delete_node_property = NULL;
+  parser->apply_textdelta = NULL;
+
+  pb->repos = repos;
+  pb->fs = svn_repos_fs(repos);
+  pb->use_history = FALSE;
+  pb->validate_props = validate_props;
+  pb->notify_func = notify_func;
+  pb->notify_baton = notify_baton;
+  pb->uuid_action = svn_repos_load_uuid_ignore; /* Never touch the UUID. */
+  pb->parent_dir = NULL;
+  pb->pool = result_pool;
+  pb->notify_pool = svn_pool_create(result_pool);
+  pb->rev_map = NULL;
+  pb->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
+  pb->last_rev_mapped = SVN_INVALID_REVNUM;
+  pb->start_rev = start_rev;
+  pb->end_rev = end_rev;
+  pb->use_pre_commit_hook = FALSE;
+  pb->use_post_commit_hook = FALSE;
+  pb->ignore_dates = ignore_dates;
+
+  *callbacks = parser;
+  *parse_baton = pb;
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_repos_load_fs_revprops(svn_repos_t *repos,
+                           svn_stream_t *dumpstream,
+                           svn_revnum_t start_rev,
+                           svn_revnum_t end_rev,
+                           svn_boolean_t validate_props,
+                           svn_boolean_t ignore_dates,
+                           svn_repos_notify_func_t notify_func,
+                           void *notify_baton,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *scratch_pool)
+{
+  const svn_repos_parse_fns3_t *parser;
+  void *parse_baton;
+
+  /* This is really simple. */
+
+  SVN_ERR(build_revprop_parser(&parser, &parse_baton,
+                               repos,
+                               start_rev, end_rev,
+                               validate_props,
+                               ignore_dates,
+                               notify_func,
+                               notify_baton,
+                               scratch_pool));
+
+  return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton, FALSE,
+                                     cancel_func, cancel_baton, scratch_pool);
+}

Modified: subversion/branches/ra-git/subversion/libsvn_repos/load.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/load.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/load.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/load.c Mon Nov 30 10:24:16 2015
@@ -385,7 +385,135 @@ parse_format_version(int *version,
   return SVN_NO_ERROR;
 }
 
+/*----------------------------------------------------------------------*/
+
+/** Dummy callback implementations for functions not provided by the user **/
+
+static svn_error_t *
+dummy_handler_magic_header_record(int version,
+                                  void *parse_baton,
+                                  apr_pool_t *pool)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_uuid_record(const char *uuid,
+                          void *parse_baton,
+                          apr_pool_t *pool)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_new_revision_record(void **revision_baton,
+                                  apr_hash_t *headers,
+                                  void *parse_baton,
+                                  apr_pool_t *pool)
+{
+  *revision_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_new_node_record(void **node_baton,
+                              apr_hash_t *headers,
+                              void *revision_baton,
+                              apr_pool_t *pool)
+{
+  *node_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_revision_property(void *revision_baton,
+                                    const char *name,
+                                    const svn_string_t *value)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_node_property(void *node_baton,
+                                const char *name,
+                                const svn_string_t *value)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_delete_node_property(void *node_baton,
+                                   const char *name)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_remove_node_props(void *node_baton)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_fulltext(svn_stream_t **stream,
+                               void *node_baton)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_apply_textdelta(svn_txdelta_window_handler_t *handler,
+                              void **handler_baton,
+                              void *node_baton)
+{
+  /* Only called by parse_text_block() and that tests for NULL handlers. */
+  *handler = NULL;
+  *handler_baton = NULL;
+  return SVN_NO_ERROR;
+}
 
+static svn_error_t *
+dummy_handler_close_node(void *node_baton)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_close_revision(void *revision_baton)
+{
+  return SVN_NO_ERROR;
+}
+
+/* Helper macro to copy the function pointer SOURCE->NAME to DEST->NAME.
+ * If the source pointer is NULL, pick the corresponding dummy handler
+ * instead. */
+#define SET_VTABLE_ENTRY(dest, source, name) \
+  dest->name = provided->name ? provided->name : dummy_handler_##name
+
+/* Return a copy of PROVIDED with all NULL callbacks replaced by a dummy
+ * handler.  Allocate the result in RESULT_POOL. */
+static const svn_repos_parse_fns3_t *
+complete_vtable(const svn_repos_parse_fns3_t *provided,
+                apr_pool_t *result_pool)
+{
+  svn_repos_parse_fns3_t *completed = apr_pcalloc(result_pool,
+                                                  sizeof(*completed));
+
+  SET_VTABLE_ENTRY(completed, provided, magic_header_record);
+  SET_VTABLE_ENTRY(completed, provided, uuid_record);
+  SET_VTABLE_ENTRY(completed, provided, new_revision_record);
+  SET_VTABLE_ENTRY(completed, provided, new_node_record);
+  SET_VTABLE_ENTRY(completed, provided, set_revision_property);
+  SET_VTABLE_ENTRY(completed, provided, set_node_property);
+  SET_VTABLE_ENTRY(completed, provided, delete_node_property);
+  SET_VTABLE_ENTRY(completed, provided, remove_node_props);
+  SET_VTABLE_ENTRY(completed, provided, set_fulltext);
+  SET_VTABLE_ENTRY(completed, provided, apply_textdelta);
+  SET_VTABLE_ENTRY(completed, provided, close_node);
+  SET_VTABLE_ENTRY(completed, provided, close_revision);
+
+  return completed;
+}
 
 /*----------------------------------------------------------------------*/
 
@@ -410,6 +538,10 @@ svn_repos_parse_dumpstream3(svn_stream_t
   apr_pool_t *nodepool = svn_pool_create(pool);
   int version;
 
+  /* Make sure we can blindly invoke callbacks. */
+  parse_fns = complete_vtable(parse_fns, pool);
+
+  /* Start parsing process. */
   SVN_ERR(svn_stream_readline(stream, &linebuf, "\n", &eof, linepool));
   if (eof)
     return stream_ran_dry();

Modified: subversion/branches/ra-git/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/log.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/log.c Mon Nov 30 10:24:16 2015
@@ -43,6 +43,7 @@
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_sorts_private.h"
+#include "private/svn_string_private.h"
 
 
 
@@ -1122,7 +1123,8 @@ fill_log_entry(svn_log_entry_t *log_entr
   if (get_revprops && want_revprops)
     {
       /* User is allowed to see at least some revprops. */
-      SVN_ERR(svn_fs_revision_proplist(&r_props, fs, rev, pool));
+      SVN_ERR(svn_fs_revision_proplist2(&r_props, fs, rev, FALSE, pool,
+                                        pool));
       if (revprops == NULL)
         {
           /* Requested all revprops... */
@@ -1150,9 +1152,9 @@ fill_log_entry(svn_log_entry_t *log_entr
              we want static initialization here and must therefore emulate
              strlen(x) by sizeof(x)-1. */
           static const svn_string_t svn_prop_revision_author
-            = {SVN_PROP_REVISION_AUTHOR, sizeof(SVN_PROP_REVISION_AUTHOR)-1};
+            = SVN__STATIC_STRING(SVN_PROP_REVISION_AUTHOR);
           static const svn_string_t svn_prop_revision_date
-            = {SVN_PROP_REVISION_DATE, sizeof(SVN_PROP_REVISION_DATE)-1};
+            = SVN__STATIC_STRING(SVN_PROP_REVISION_DATE);
 
           /* often only the standard revprops got requested and delivered.
              In that case, we can simply pass the hash on. */
@@ -1907,8 +1909,7 @@ store_search(svn_mergeinfo_t processed,
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
       svn_rangelist_t *ranges = apr_array_make(processed_pool, 1,
                                                sizeof(svn_merge_range_t*));
-      svn_merge_range_t *range = apr_palloc(processed_pool,
-                                            sizeof(svn_merge_range_t));
+      svn_merge_range_t *range = apr_palloc(processed_pool, sizeof(*range));
 
       range->start = start;
       range->end = end;
@@ -2176,7 +2177,7 @@ do_logs(svn_fs_t *fs,
           if (rev_mergeinfo)
             {
               struct added_deleted_mergeinfo *add_and_del_mergeinfo =
-                apr_hash_get(rev_mergeinfo, &current, sizeof(svn_revnum_t));
+                apr_hash_get(rev_mergeinfo, &current, sizeof(current));
               added_mergeinfo = add_and_del_mergeinfo->added_mergeinfo;
               deleted_mergeinfo = add_and_del_mergeinfo->deleted_mergeinfo;
               has_children = (apr_hash_count(added_mergeinfo) > 0
@@ -2341,6 +2342,10 @@ svn_repos_get_logs4(svn_repos_t *repos,
       revprops = new_revprops;
     }
 
+  /* Make sure we catch up on the latest revprop changes.  This is the only
+   * time we will refresh the revprop data in this query. */
+  SVN_ERR(svn_fs_refresh_revision_props(fs, pool));
+
   /* Setup log range. */
   SVN_ERR(svn_fs_youngest_rev(&head, fs, pool));
 

Modified: subversion/branches/ra-git/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/replay.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/replay.c Mon Nov 30 10:24:16 2015
@@ -555,10 +555,6 @@ path_driver_cb_func(void **dir_baton,
         return svn_error_create(SVN_ERR_FS_ALREADY_EXISTS, NULL,
                                 _("Root directory already exists."));
 
-      /* A NULL parent_baton will cause a segfault.  It should never be
-          NULL for non-root paths. */
-      SVN_ERR_ASSERT(parent_baton);
-
       /* Was this node copied? */
       SVN_ERR(fill_copyfrom(&copyfrom_root, &copyfrom_path, &copyfrom_rev,
                             &src_readable, root, change,
@@ -971,6 +967,11 @@ svn_repos_replay2(svn_fs_root_t *root,
   const char *repos_root = "";
   void *unlock_baton;
 
+  /* If we were not given a low water mark, assume that everything is there,
+     all the way back to revision 0. */
+  if (! SVN_IS_VALID_REVNUM(low_water_mark))
+    low_water_mark = 0;
+
   /* Special-case r0, which we know is an empty revision; if we don't
      special-case it we might end up trying to compare it to "r-1". */
   if (svn_fs_is_revision_root(root)
@@ -1493,7 +1494,7 @@ svn_repos__replay_ev2(svn_fs_root_t *roo
   svn_error_t *err = SVN_NO_ERROR;
   int i;
 
-  SVN_ERR_ASSERT(!svn_dirent_is_absolute(base_repos_relpath));
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(base_repos_relpath));
 
   /* Special-case r0, which we know is an empty revision; if we don't
      special-case it we might end up trying to compare it to "r-1". */

Modified: subversion/branches/ra-git/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/reporter.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/reporter.c Mon Nov 30 10:24:16 2015
@@ -481,10 +481,12 @@ get_revision_info(report_baton_t *b,
     {
       /* Info is not available, yet.
          Get all revprops. */
-      SVN_ERR(svn_fs_revision_proplist(&r_props,
-                                       b->repos->fs,
-                                       rev,
-                                       scratch_pool));
+      SVN_ERR(svn_fs_revision_proplist2(&r_props,
+                                        b->repos->fs,
+                                        rev,
+                                        FALSE,
+                                        scratch_pool,
+                                        scratch_pool));
 
       /* Extract the committed-date. */
       cdate = svn_hash_gets(r_props, SVN_PROP_REVISION_DATE);
@@ -1282,7 +1284,7 @@ delta_dirs(report_baton_t *b, svn_revnum
 
       /* Loop over the dirents in the target. */
       SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
-                                       t_entries, subpool));
+                                       t_entries, subpool, iterpool));
       for (i = 0; i < t_ordered_entries->nelts; ++i)
         {
           const svn_fs_dirent_t *t_entry
@@ -1548,6 +1550,7 @@ svn_repos_finish_report(void *baton, apr
 {
   report_baton_t *b = baton;
 
+  SVN_ERR(svn_fs_refresh_revision_props(svn_repos_fs(b->repos), pool));
   return svn_error_trace(finish_report(b, pool));
 }
 

Modified: subversion/branches/ra-git/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/repos.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/repos.c Mon Nov 30 10:24:16 2015
@@ -393,15 +393,15 @@ create_hooks(svn_repos_t *repos, apr_poo
 "# e.g.: \"" SVN_RA_CAPABILITY_MERGEINFO ":some-other-capability\" "         \
   "(the order is undefined)."                                                NL
 "#"                                                                          NL
+"# The list is self-reported by the client.  Therefore, you should not"      NL
+"# make security assumptions based on the capabilities list, nor should"     NL
+"# you assume that clients reliably report every capability they have."      NL
+"#"                                                                          NL
 "# Note: The TXN-NAME parameter is new in Subversion 1.8.  Prior to version" NL
 "# 1.8, the start-commit hook was invoked before the commit txn was even"    NL
 "# created, so the ability to inspect the commit txn and its metadata from"  NL
 "# within the start-commit hook was not possible."                           NL
 "# "                                                                         NL
-"# The list is self-reported by the client.  Therefore, you should not"      NL
-"# make security assumptions based on the capabilities list, nor should"     NL
-"# you assume that clients reliably report every capability they have."      NL
-"#"                                                                          NL
 "# If the hook program exits with success, the commit continues; but"        NL
 "# if it exits with failure (non-zero), the commit is stopped before"        NL
 "# a Subversion txn is created, and STDERR is returned to the client."       NL;
@@ -1175,8 +1175,8 @@ svn_repos_create(svn_repos_t **repos_p,
   SVN_ERR(lock_repos(repos, FALSE, FALSE, scratch_pool));
 
   /* Create an environment for the filesystem. */
-  if ((err = svn_fs_create(&repos->fs, repos->db_path, fs_config,
-                           result_pool)))
+  if ((err = svn_fs_create2(&repos->fs, repos->db_path, fs_config,
+                            result_pool, scratch_pool)))
     {
       /* If there was an error making the filesytem, e.g. unknown/supported
        * filesystem type.  Clean up after ourselves.  Yes this is safe because
@@ -1635,9 +1635,10 @@ svn_repos_fs(svn_repos_t *repos)
 }
 
 const char *
-svn_repos_fs_type(svn_repos_t *repos, apr_pool_t *pool)
+svn_repos_fs_type(svn_repos_t *repos,
+                  apr_pool_t *result_pool)
 {
-  return apr_pstrdup(pool, repos->fs_type);
+  return apr_pstrdup(result_pool, repos->fs_type);
 }
 
 /* For historical reasons, for the Berkeley DB backend, this code uses
@@ -1957,7 +1958,7 @@ svn_repos_hotcopy3(const char *src_path,
                    void *notify_baton,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
-                   apr_pool_t *pool)
+                   apr_pool_t *scratch_pool)
 {
   svn_fs_hotcopy_notify_t fs_notify_func;
   struct fs_hotcopy_notify_baton_t fs_notify_baton;
@@ -1968,8 +1969,8 @@ svn_repos_hotcopy3(const char *src_path,
   svn_repos_t *dst_repos;
   svn_error_t *err;
 
-  SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, pool));
-  SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, pool));
+  SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, scratch_pool));
+  SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, scratch_pool));
   if (strcmp(src_abspath, dst_abspath) == 0)
     return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
                              _("Hotcopy source and destination are equal"));
@@ -1979,7 +1980,7 @@ svn_repos_hotcopy3(const char *src_path,
                     FALSE, FALSE,
                     FALSE,    /* don't try to open the db yet. */
                     NULL,
-                    pool, pool));
+                    scratch_pool, scratch_pool));
 
   /* If we are going to clean logs, then get an exclusive lock on
      db-logs.lock, to ensure that no one else will work with logs.
@@ -1987,7 +1988,7 @@ svn_repos_hotcopy3(const char *src_path,
      If we are just copying, then get a shared lock to ensure that
      no one else will clean logs while we copying them */
 
-  SVN_ERR(lock_db_logs_file(src_repos, clean_logs, pool));
+  SVN_ERR(lock_db_logs_file(src_repos, clean_logs, scratch_pool));
 
   /* Copy the repository to a new path, with exception of
      specially handled directories */
@@ -2001,16 +2002,16 @@ svn_repos_hotcopy3(const char *src_path,
                            0,
                            hotcopy_structure,
                            &hotcopy_context,
-                           pool));
+                           scratch_pool));
 
   /* Prepare dst_repos object so that we may create locks,
      so that we may open repository */
 
-  dst_repos = create_svn_repos_t(dst_abspath, pool);
+  dst_repos = create_svn_repos_t(dst_abspath, scratch_pool);
   dst_repos->fs_type = src_repos->fs_type;
   dst_repos->format = src_repos->format;
 
-  err = create_locks(dst_repos, pool);
+  err = create_locks(dst_repos, scratch_pool);
   if (err)
     {
       if (incremental && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
@@ -2019,7 +2020,8 @@ svn_repos_hotcopy3(const char *src_path,
         return svn_error_trace(err);
     }
 
-  err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool);
+  err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT,
+                             scratch_pool);
   if (err)
     {
       if (incremental && APR_STATUS_IS_EEXIST(err->apr_err))
@@ -2030,7 +2032,7 @@ svn_repos_hotcopy3(const char *src_path,
 
   /* Exclusively lock the new repository.
      No one should be accessing it at the moment */
-  SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, pool));
+  SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, scratch_pool));
 
   fs_notify_func = notify_func ? fs_hotcopy_notify : NULL;
   fs_notify_baton.notify_func = notify_func;
@@ -2039,12 +2041,12 @@ svn_repos_hotcopy3(const char *src_path,
   SVN_ERR(svn_fs_hotcopy3(src_repos->db_path, dst_repos->db_path,
                           clean_logs, incremental,
                           fs_notify_func, &fs_notify_baton,
-                          cancel_func, cancel_baton, pool));
+                          cancel_func, cancel_baton, scratch_pool));
 
   /* Destination repository is ready.  Stamp it with a format number. */
   return svn_io_write_version_file
-          (svn_dirent_join(dst_repos->path, SVN_REPOS__FORMAT, pool),
-           dst_repos->format, pool);
+          (svn_dirent_join(dst_repos->path, SVN_REPOS__FORMAT, scratch_pool),
+           dst_repos->format, scratch_pool);
 }
 
 /* Return the library version number. */
@@ -2065,7 +2067,6 @@ svn_repos_stat(svn_dirent_t **dirent,
   svn_node_kind_t kind;
   svn_dirent_t *ent;
   const char *datestring;
-  apr_hash_t *prophash;
 
   SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
 
@@ -2081,9 +2082,7 @@ svn_repos_stat(svn_dirent_t **dirent,
   if (kind == svn_node_file)
     SVN_ERR(svn_fs_file_length(&(ent->size), root, path, pool));
 
-  SVN_ERR(svn_fs_node_proplist(&prophash, root, path, pool));
-  if (apr_hash_count(prophash) > 0)
-    ent->has_props = TRUE;
+  SVN_ERR(svn_fs_node_has_props(&ent->has_props, root, path, pool));
 
   SVN_ERR(svn_repos_get_committed_info(&(ent->created_rev),
                                        &datestring,

Modified: subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_repos/rev_hunt.c Mon Nov 30 10:24:16 2015
@@ -44,7 +44,7 @@
 
 /* Note:  this binary search assumes that the datestamp properties on
    each revision are in chronological order.  That is if revision A >
-   revision B, then A's datestamp is younger then B's datestamp.
+   revision B, then A's datestamp is younger than B's datestamp.
 
    If someone comes along and sets a bogus datestamp, this routine
    might not work right.
@@ -65,8 +65,8 @@ get_time(apr_time_t *tm,
 {
   svn_string_t *date_str;
 
-  SVN_ERR(svn_fs_revision_prop(&date_str, fs, rev, SVN_PROP_REVISION_DATE,
-                               pool));
+  SVN_ERR(svn_fs_revision_prop2(&date_str, fs, rev, SVN_PROP_REVISION_DATE,
+                                FALSE, pool, pool));
   if (! date_str)
     return svn_error_createf
       (SVN_ERR_FS_GENERAL, NULL,
@@ -88,6 +88,7 @@ svn_repos_dated_revision(svn_revnum_t *r
 
   /* Initialize top and bottom values of binary search. */
   SVN_ERR(svn_fs_youngest_rev(&rev_latest, fs, pool));
+  SVN_ERR(svn_fs_refresh_revision_props(fs, pool));
   rev_bot = 0;
   rev_top = rev_latest;
 
@@ -170,7 +171,8 @@ svn_repos_get_committed_info(svn_revnum_
   SVN_ERR(svn_fs_node_created_rev(committed_rev, root, path, pool));
 
   /* Get the revision properties of this revision. */
-  SVN_ERR(svn_fs_revision_proplist(&revprops, fs, *committed_rev, pool));
+  SVN_ERR(svn_fs_revision_proplist2(&revprops, fs, *committed_rev, TRUE,
+                                    pool, pool));
 
   /* Extract date and author from these revprops. */
   committed_date_s = svn_hash_gets(revprops, SVN_PROP_REVISION_DATE);
@@ -310,9 +312,8 @@ svn_repos_deleted_rev(svn_fs_t *fs,
                       svn_revnum_t *deleted,
                       apr_pool_t *pool)
 {
-  apr_pool_t *subpool;
-  svn_fs_root_t *start_root, *root, *copy_root;
-  const char *copy_path;
+  apr_pool_t *iterpool;
+  svn_fs_root_t *start_root, *root;
   svn_revnum_t mid_rev;
   svn_node_kind_t kind;
   svn_fs_node_relation_t node_relation;
@@ -379,6 +380,8 @@ svn_repos_deleted_rev(svn_fs_t *fs,
                                    root, path, pool));
       if (node_relation != svn_fs_node_unrelated)
         {
+          svn_fs_root_t *copy_root;
+          const char *copy_path;
           SVN_ERR(svn_fs_closest_copy(&copy_root, &copy_path, root,
                                       path, pool));
           if (!copy_root ||
@@ -432,15 +435,15 @@ svn_repos_deleted_rev(svn_fs_t *fs,
   */
 
   mid_rev = (start + end) / 2;
-  subpool = svn_pool_create(pool);
+  iterpool = svn_pool_create(pool);
 
   while (1)
     {
-      svn_pool_clear(subpool);
+      svn_pool_clear(iterpool);
 
       /* Get revision root and node id for mid_rev at that revision. */
-      SVN_ERR(svn_fs_revision_root(&root, fs, mid_rev, subpool));
-      SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
+      SVN_ERR(svn_fs_revision_root(&root, fs, mid_rev, iterpool));
+      SVN_ERR(svn_fs_check_path(&kind, root, path, iterpool));
       if (kind == svn_node_none)
         {
           /* Case D: Look lower in the range. */
@@ -449,13 +452,15 @@ svn_repos_deleted_rev(svn_fs_t *fs,
         }
       else
         {
+          svn_fs_root_t *copy_root;
+          const char *copy_path;
           /* Determine the relationship between the start node
              and the current node. */
           SVN_ERR(svn_fs_node_relation(&node_relation, start_root, path,
-                                       root, path, pool));
+                                       root, path, iterpool));
           if (node_relation != svn_fs_node_unrelated)
-          SVN_ERR(svn_fs_closest_copy(&copy_root, &copy_path, root,
-                                      path, subpool));
+            SVN_ERR(svn_fs_closest_copy(&copy_root, &copy_path, root,
+                                        path, iterpool));
           if (node_relation == svn_fs_node_unrelated ||
               (copy_root &&
                (svn_fs_revision_root_revision(copy_root) > start)))
@@ -479,7 +484,7 @@ svn_repos_deleted_rev(svn_fs_t *fs,
         }
     }
 
-  svn_pool_destroy(subpool);
+  svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
@@ -666,8 +671,7 @@ svn_repos_trace_node_locations(svn_fs_t
   /* First - let's sort the array of the revisions from the greatest revision
    * downward, so it will be easier to search on. */
   location_revisions = apr_array_copy(pool, location_revisions_orig);
-  qsort(location_revisions->elts, location_revisions->nelts,
-        sizeof(*revision_ptr), svn_sort_compare_revisions);
+  svn_sort__array(location_revisions, svn_sort_compare_revisions);
 
   revision_ptr = (svn_revnum_t *)location_revisions->elts;
   revision_ptr_end = revision_ptr + location_revisions->nelts;
@@ -708,23 +712,6 @@ svn_repos_trace_node_locations(svn_fs_t
       if (! prev_path)
         break;
 
-      if (authz_read_func)
-        {
-          svn_boolean_t readable;
-          svn_fs_root_t *tmp_root;
-
-          SVN_ERR(svn_fs_revision_root(&tmp_root, fs, revision, currpool));
-          SVN_ERR(authz_read_func(&readable, tmp_root, path,
-                                  authz_read_baton, currpool));
-          if (! readable)
-            {
-              svn_pool_destroy(lastpool);
-              svn_pool_destroy(currpool);
-
-              return SVN_NO_ERROR;
-            }
-        }
-
       /* Assign the current path to all younger revisions until we reach
          the copy target rev. */
       while ((revision_ptr < revision_ptr_end)
@@ -747,6 +734,20 @@ svn_repos_trace_node_locations(svn_fs_t
       path = prev_path;
       revision = prev_rev;
 
+      if (authz_read_func)
+        {
+          svn_boolean_t readable;
+          SVN_ERR(svn_fs_revision_root(&root, fs, revision, currpool));
+          SVN_ERR(authz_read_func(&readable, root, path,
+                                  authz_read_baton, currpool));
+          if (!readable)
+            {
+              svn_pool_destroy(lastpool);
+              svn_pool_destroy(currpool);
+              return SVN_NO_ERROR;
+            }
+        }
+
       /* Clear last pool and switch. */
       svn_pool_clear(lastpool);
       tmppool = lastpool;
@@ -835,27 +836,32 @@ svn_repos_node_location_segments(svn_rep
 {
   svn_fs_t *fs = svn_repos_fs(repos);
   svn_stringbuf_t *current_path;
-  svn_revnum_t youngest_rev = SVN_INVALID_REVNUM, current_rev;
+  svn_revnum_t youngest_rev, current_rev;
   apr_pool_t *subpool;
 
+  SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
+
   /* No PEG_REVISION?  We'll use HEAD. */
   if (! SVN_IS_VALID_REVNUM(peg_revision))
-    {
-      SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
-      peg_revision = youngest_rev;
-    }
+    peg_revision = youngest_rev;
+
+  if (peg_revision > youngest_rev)
+    return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                             _("No such revision %ld"), peg_revision);
 
-  /* No START_REV?  We'll use HEAD (which we may have already fetched). */
+  /* No START_REV?  We'll use peg rev. */
   if (! SVN_IS_VALID_REVNUM(start_rev))
-    {
-      if (SVN_IS_VALID_REVNUM(youngest_rev))
-        start_rev = youngest_rev;
-      else
-        SVN_ERR(svn_fs_youngest_rev(&start_rev, fs, pool));
-    }
+    start_rev = peg_revision;
+  else if (start_rev > peg_revision)
+    return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                             _("No such revision %ld"), start_rev);
 
   /* No END_REV?  We'll use 0. */
-  end_rev = SVN_IS_VALID_REVNUM(end_rev) ? end_rev : 0;
+  if (! SVN_IS_VALID_REVNUM(end_rev))
+    end_rev = 0;
+  else if (end_rev > start_rev)
+    return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                             _("No such revision %ld"), end_rev);
 
   /* Are the revision properly ordered?  They better be -- the API
      demands it. */
@@ -1329,6 +1335,7 @@ struct send_baton
   apr_hash_t *last_props;
   const char *last_path;
   svn_fs_root_t *last_root;
+  svn_boolean_t include_merged_revisions;
 };
 
 /* Send PATH_REV to HANDLER and HANDLER_BATON, using information provided by
@@ -1349,32 +1356,75 @@ send_path_revision(struct path_revision
   void *delta_baton = NULL;
   apr_pool_t *tmp_pool;  /* For swapping */
   svn_boolean_t contents_changed;
+  svn_boolean_t props_changed;
 
   svn_pool_clear(sb->iterpool);
 
   /* Get the revision properties. */
-  SVN_ERR(svn_fs_revision_proplist(&rev_props, repos->fs,
-                                   path_rev->revnum, sb->iterpool));
+  SVN_ERR(svn_fs_revision_proplist2(&rev_props, repos->fs,
+                                    path_rev->revnum, FALSE,
+                                    sb->iterpool, sb->iterpool));
 
   /* Open the revision root. */
   SVN_ERR(svn_fs_revision_root(&root, repos->fs, path_rev->revnum,
                                sb->iterpool));
 
-  /* Get the file's properties for this revision and compute the diffs. */
-  SVN_ERR(svn_fs_node_proplist(&props, root, path_rev->path,
-                                   sb->iterpool));
-  SVN_ERR(svn_prop_diffs(&prop_diffs, props, sb->last_props,
-                         sb->iterpool));
-
-  /* Check if the contents *may* have changed. (Allow false positives,
-     for now, as the blame implementation currently depends on them.) */
-  /* Special case: In the first revision, we always provide a delta. */
+  /* Check if the props *may* have changed. */
   if (sb->last_root)
-    SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
-                                      sb->last_path, root, path_rev->path,
-                                      sb->iterpool));
+    {
+      /* We don't use svn_fs_props_different() because it's more
+       * expensive. */
+      SVN_ERR(svn_fs_props_changed(&props_changed,
+                                   sb->last_root, sb->last_path,
+                                   root, path_rev->path, sb->iterpool));
+    }
   else
-    contents_changed = TRUE;
+    {
+      props_changed = TRUE;
+    }
+
+  /* Calculate actual difference between last and current properties. */
+  if (props_changed)
+    {
+      /* Get the file's properties for this revision and compute the diffs. */
+      SVN_ERR(svn_fs_node_proplist(&props, root, path_rev->path,
+                                   sb->iterpool));
+      SVN_ERR(svn_prop_diffs(&prop_diffs, props, sb->last_props,
+                             sb->iterpool));
+    }
+  else
+    {
+      /* Properties didn't change: copy  LAST_PROPS to current POOL. */
+      props = svn_prop_hash_dup(sb->last_props, sb->iterpool);
+      prop_diffs = apr_array_make(sb->iterpool, 0, sizeof(svn_prop_t));
+    }
+
+  /* Check if the contents *may* have changed. */
+  if (! sb->last_root)
+    {
+      /* Special case: In the first revision, we always provide a delta. */
+      contents_changed = TRUE;
+    }
+  else if (sb->include_merged_revisions
+           && strcmp(sb->last_path, path_rev->path))
+    {
+      /* ### This is a HACK!!!
+       * Blame -g, in older clients anyways, relies on getting a notification
+       * whenever the path changes - even if there was no content change.
+       *
+       * TODO: A future release should take an extra parameter and depending
+       * on that either always send a text delta or only send it if there
+       * is a difference. */
+      contents_changed = TRUE;
+    }
+  else
+    {
+      /* Did the file contents actually change?
+       * It could e.g. be a property-only change. */
+      SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
+                                        sb->last_path, root, path_rev->path,
+                                        sb->iterpool));
+    }
 
   /* We have all we need, give to the handler. */
   SVN_ERR(handler(handler_baton, path_rev->path, path_rev->revnum,
@@ -1443,6 +1493,7 @@ get_file_revs_backwards(svn_repos_t *rep
   last_pool = svn_pool_create(scratch_pool);
   sb.iterpool = svn_pool_create(scratch_pool);
   sb.last_pool = svn_pool_create(scratch_pool);
+  sb.include_merged_revisions = FALSE;
 
   /* We want the first txdelta to be against the empty file. */
   sb.last_root = NULL;
@@ -1571,6 +1622,10 @@ svn_repos_get_file_revs2(svn_repos_t *re
         end = youngest_rev;
     }
 
+  /* Make sure we catch up on the latest revprop changes.  This is the only
+   * time we will refresh the revprop data in this query. */
+  SVN_ERR(svn_fs_refresh_revision_props(repos->fs, scratch_pool));
+
   if (end < start)
     {
       if (include_merged_revisions)
@@ -1598,6 +1653,9 @@ svn_repos_get_file_revs2(svn_repos_t *re
   /* Create an empty hash table for the first property diff. */
   sb.last_props = apr_hash_make(sb.last_pool);
 
+  /* Inform send_path_revision() whether workarounds / special behavior
+   * may be needed. */
+  sb.include_merged_revisions = include_merged_revisions;
 
   /* Get the revisions we are interested in. */
   duplicate_path_revs = apr_hash_make(scratch_pool);

Propchange: subversion/branches/ra-git/subversion/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Nov 30 10:24:16 2015
@@ -12,3 +12,4 @@ internal_statements.h
 errorcode.inc
 libsvn_subr.pc.in
 libsvn_subr.pc
+config_keys.inc

Modified: subversion/branches/ra-git/subversion/libsvn_subr/atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/atomic.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/atomic.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/atomic.c Mon Nov 30 10:24:16 2015
@@ -20,8 +20,13 @@
  * ====================================================================
  */
 
+#include <assert.h>
 #include <apr_time.h>
+
+#include "svn_pools.h"
+
 #include "private/svn_atomic.h"
+#include "private/svn_mutex.h"
 
 /* Magic values for atomic initialization */
 #define SVN_ATOMIC_UNINITIALIZED 0
@@ -29,11 +34,21 @@
 #define SVN_ATOMIC_INIT_FAILED   2
 #define SVN_ATOMIC_INITIALIZED   3
 
-svn_error_t*
-svn_atomic__init_once(volatile svn_atomic_t *global_status,
-                      svn_error_t *(*init_func)(void*,apr_pool_t*),
-                      void *baton,
-                      apr_pool_t* pool)
+
+/* Baton used by init_funct_t and init_once(). */
+typedef struct init_baton_t init_baton_t;
+
+/* Initialization function wrapper. Hides API details from init_once().
+   The implementation must return FALSE on failure. */
+typedef svn_boolean_t (*init_func_t)(init_baton_t *init_baton);
+
+/*
+ * This is the actual atomic initialization driver.
+ * Returns FALSE on failure.
+ */
+static svn_boolean_t
+init_once(volatile svn_atomic_t *global_status,
+          init_func_t init_func, init_baton_t *init_baton)
 {
   /* !! Don't use localizable strings in this function, because these
      !! might cause deadlocks. This function can be used to initialize
@@ -42,44 +57,162 @@ svn_atomic__init_once(volatile svn_atomi
   /* We have to call init_func exactly once.  Because APR
      doesn't have statically-initialized mutexes, we implement a poor
      man's spinlock using svn_atomic_cas. */
+
   svn_atomic_t status = svn_atomic_cas(global_status,
                                        SVN_ATOMIC_START_INIT,
                                        SVN_ATOMIC_UNINITIALIZED);
 
-  if (status == SVN_ATOMIC_UNINITIALIZED)
+  for (;;)
     {
-      svn_error_t *err = init_func(baton, pool);
-      if (err)
+      switch (status)
         {
-#if APR_HAS_THREADS
-          /* Tell other threads that the initialization failed. */
-          svn_atomic_cas(global_status,
-                         SVN_ATOMIC_INIT_FAILED,
-                         SVN_ATOMIC_START_INIT);
-#endif
-          return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err,
-                                  "Couldn't perform atomic initialization");
+        case SVN_ATOMIC_UNINITIALIZED:
+          {
+            const svn_boolean_t result = init_func(init_baton);
+            const svn_atomic_t init_state = (result
+                                             ? SVN_ATOMIC_INITIALIZED
+                                             : SVN_ATOMIC_INIT_FAILED);
+
+            svn_atomic_cas(global_status, init_state,
+                           SVN_ATOMIC_START_INIT);
+            return result;
+          }
+
+        case SVN_ATOMIC_START_INIT:
+          /* Wait for the init function to complete. */
+          apr_sleep(APR_USEC_PER_SEC / 1000);
+          status = svn_atomic_cas(global_status,
+                                  SVN_ATOMIC_UNINITIALIZED,
+                                  SVN_ATOMIC_UNINITIALIZED);
+          continue;
+
+        case SVN_ATOMIC_INIT_FAILED:
+          return FALSE;
+
+        case SVN_ATOMIC_INITIALIZED:
+          return TRUE;
+
+        default:
+          /* Something went seriously wrong with the atomic operations. */
+          abort();
         }
-      svn_atomic_cas(global_status,
-                     SVN_ATOMIC_INITIALIZED,
-                     SVN_ATOMIC_START_INIT);
-    }
-#if APR_HAS_THREADS
-  /* Wait for whichever thread is performing initialization to finish. */
-  /* XXX FIXME: Should we have a maximum wait here, like we have in
-                the Windows file IO spinner? */
-  else while (status != SVN_ATOMIC_INITIALIZED)
-    {
-      if (status == SVN_ATOMIC_INIT_FAILED)
-        return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, NULL,
-                                "Couldn't perform atomic initialization");
-
-      apr_sleep(APR_USEC_PER_SEC / 1000);
-      status = svn_atomic_cas(global_status,
-                              SVN_ATOMIC_UNINITIALIZED,
-                              SVN_ATOMIC_UNINITIALIZED);
     }
-#endif /* APR_HAS_THREADS */
+}
+
+
+/* This baton structure is used by the two flavours of init-once APIs
+   to hide their differences from the init_once() driver. Each private
+   API uses only selected parts of the baton.
+
+   No part of this structure changes unless a wrapped init function is
+   actually invoked by init_once().
+*/
+struct init_baton_t
+{
+  /* Used only by svn_atomic__init_once()/err_init_func_wrapper() */
+  svn_atomic__err_init_func_t err_init_func;
+  svn_error_t *err;
+  apr_pool_t *pool;
+
+  /* Used only by svn_atomic__init_no_error()/str_init_func_wrapper() */
+  svn_atomic__str_init_func_t str_init_func;
+  const char *errstr;
+
+  /* Used by both pairs of functions */
+  void *baton;
+};
+
+/* Wrapper for the svn_atomic__init_once init function. */
+static svn_boolean_t err_init_func_wrapper(init_baton_t *init_baton)
+{
+  init_baton->err = init_baton->err_init_func(init_baton->baton,
+                                              init_baton->pool);
+  return (init_baton->err == SVN_NO_ERROR);
+}
+
+svn_error_t *
+svn_atomic__init_once(volatile svn_atomic_t *global_status,
+                      svn_atomic__err_init_func_t err_init_func,
+                      void *baton,
+                      apr_pool_t* pool)
+{
+  init_baton_t init_baton;
+  init_baton.err_init_func = err_init_func;
+  init_baton.err = NULL;
+  init_baton.pool = pool;
+  init_baton.baton = baton;
+
+  if (init_once(global_status, err_init_func_wrapper, &init_baton))
+    return SVN_NO_ERROR;
+
+  return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, init_baton.err,
+                          "Couldn't perform atomic initialization");
+}
+
 
+/* Wrapper for the svn_atomic__init_no_error init function. */
+static svn_boolean_t str_init_func_wrapper(init_baton_t *init_baton)
+{
+  init_baton->errstr = init_baton->str_init_func(init_baton->baton);
+  return (init_baton->errstr == NULL);
+}
+
+const char *
+svn_atomic__init_once_no_error(volatile svn_atomic_t *global_status,
+                               svn_atomic__str_init_func_t str_init_func,
+                               void *baton)
+{
+  init_baton_t init_baton;
+  init_baton.str_init_func = str_init_func;
+  init_baton.errstr = NULL;
+  init_baton.baton = baton;
+
+  if (init_once(global_status, str_init_func_wrapper, &init_baton))
+    return NULL;
+
+  /* Our init function wrapper may not have been called; make sure
+     that we return generic error message in that case. */
+  if (!init_baton.errstr)
+    return "Couldn't perform atomic initialization";
+  else
+    return init_baton.errstr;
+}
+
+/* The process-global counter that we use to produce process-wide unique
+ * values.  Since APR has no 64 bit atomics, all access to this will be
+ * serialized through COUNTER_MUTEX. */
+static apr_uint64_t uniqiue_counter = 0;
+
+/* The corresponding mutex and initialization state. */
+static volatile svn_atomic_t counter_status = SVN_ATOMIC_UNINITIALIZED;
+static svn_mutex__t *counter_mutex = NULL;
+
+/* svn_atomic__err_init_func_t implementation that initializes COUNTER_MUTEX.
+ * Note that neither argument will be used and should be NULL. */
+static svn_error_t *
+init_unique_counter(void *null_baton,
+                    apr_pool_t *null_pool)
+{
+  /* COUNTER_MUTEX is global, so it needs to live in a global pool.
+   * APR also makes those thread-safe by default. */
+  SVN_ERR(svn_mutex__init(&counter_mutex, TRUE, svn_pool_create(NULL)));
+  return SVN_NO_ERROR;
+}
+
+/* Read and increment UNIQIUE_COUNTER. Return the new value in *VALUE.
+ * Call this function only while having acquired the COUNTER_MUTEX. */
+static svn_error_t *
+read_unique_counter(apr_uint64_t *value)
+{
+  *value = ++uniqiue_counter;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_atomic__unique_counter(apr_uint64_t *value)
+{
+  SVN_ERR(svn_atomic__init_once(&counter_status, init_unique_counter, NULL,
+                                NULL));
+  SVN_MUTEX__WITH_LOCK(counter_mutex, read_unique_counter(value));
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/auth.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/auth.c Mon Nov 30 10:24:16 2015
@@ -109,10 +109,10 @@ struct svn_auth_baton_t
 
   /* run-time parameters needed by providers. */
   apr_hash_t *parameters;
+  apr_hash_t *slave_parameters;
 
   /* run-time credentials cache. */
   apr_hash_t *creds_cache;
-
 };
 
 /* Abstracted iteration baton */
@@ -125,6 +125,7 @@ struct svn_auth_iterstate_t
   const char *realmstring;      /* The original realmstring passed in */
   const char *cache_key;        /* key to use in auth_baton's creds_cache */
   svn_auth_baton_t *auth_baton; /* the original auth_baton. */
+  apr_hash_t *parameters;
 };
 
 
@@ -142,6 +143,7 @@ svn_auth_open(svn_auth_baton_t **auth_ba
   ab = apr_pcalloc(pool, sizeof(*ab));
   ab->tables = apr_hash_make(pool);
   ab->parameters = apr_hash_make(pool);
+  /* ab->slave_parameters = NULL; */
   ab->creds_cache = apr_hash_make(pool);
   ab->pool = pool;
 
@@ -170,7 +172,8 @@ svn_auth_open(svn_auth_baton_t **auth_ba
   *auth_baton = ab;
 }
 
-
+/* Magic pointer value to allow storing 'NULL' in an apr_hash_t */
+static const void *auth_NULL = NULL;
 
 void
 svn_auth_set_parameter(svn_auth_baton_t *auth_baton,
@@ -178,17 +181,35 @@ svn_auth_set_parameter(svn_auth_baton_t
                        const void *value)
 {
   if (auth_baton)
-    svn_hash_sets(auth_baton->parameters, name, value);
+    {
+      if (auth_baton->slave_parameters)
+        {
+          if (!value)
+            value = &auth_NULL;
+
+          svn_hash_sets(auth_baton->slave_parameters, name, value);
+        }
+      else
+        svn_hash_sets(auth_baton->parameters, name, value);
+    }
 }
 
 const void *
 svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
                        const char *name)
 {
-  if (auth_baton)
-    return svn_hash_gets(auth_baton->parameters, name);
-  else
+  const void *value;
+  if (!auth_baton)
     return NULL;
+  else if (!auth_baton->slave_parameters)
+    return svn_hash_gets(auth_baton->parameters, name);
+
+  value = svn_hash_gets(auth_baton->slave_parameters, name);
+
+  if (value)
+    return (value == &auth_NULL ? NULL : value);
+
+  return svn_hash_gets(auth_baton->parameters, name);
 }
 
 
@@ -218,6 +239,7 @@ svn_auth_first_credentials(void **creden
   svn_boolean_t got_first = FALSE;
   svn_auth_iterstate_t *iterstate;
   const char *cache_key;
+  apr_hash_t *parameters;
 
   if (! auth_baton)
     return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
@@ -230,6 +252,26 @@ svn_auth_first_credentials(void **creden
                              _("No provider registered for '%s' credentials"),
                              cred_kind);
 
+  if (auth_baton->slave_parameters)
+    {
+      apr_hash_index_t *hi;
+      parameters = apr_hash_copy(pool, auth_baton->parameters);
+
+      for (hi = apr_hash_first(pool, auth_baton->slave_parameters);
+            hi;
+            hi = apr_hash_next(hi))
+        {
+          const void *value = apr_hash_this_val(hi);
+
+          if (value == &auth_NULL)
+            value = NULL;
+
+          svn_hash_sets(parameters, apr_hash_this_key(hi), value);
+        }
+    }
+  else
+    parameters = auth_baton->parameters;
+
   /* First, see if we have cached creds in the auth_baton. */
   cache_key = make_cache_key(cred_kind, realmstring, pool);
   creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
@@ -247,7 +289,7 @@ svn_auth_first_credentials(void **creden
                                    svn_auth_provider_object_t *);
           SVN_ERR(provider->vtable->first_credentials(&creds, &iter_baton,
                                                       provider->provider_baton,
-                                                      auth_baton->parameters,
+                                                      parameters,
                                                       realmstring,
                                                       auth_baton->pool));
 
@@ -274,6 +316,7 @@ svn_auth_first_credentials(void **creden
       iterstate->realmstring = apr_pstrdup(pool, realmstring);
       iterstate->cache_key = cache_key;
       iterstate->auth_baton = auth_baton;
+      iterstate->parameters = parameters;
       *state = iterstate;
 
       /* Put the creds in the cache */
@@ -310,7 +353,7 @@ svn_auth_next_credentials(void **credent
         {
           SVN_ERR(provider->vtable->first_credentials(
                       &creds, &(state->provider_iter_baton),
-                      provider->provider_baton, auth_baton->parameters,
+                      provider->provider_baton, state->parameters,
                       state->realmstring, auth_baton->pool));
           state->got_first = TRUE;
         }
@@ -319,7 +362,7 @@ svn_auth_next_credentials(void **credent
           SVN_ERR(provider->vtable->next_credentials(&creds,
                                                      state->provider_iter_baton,
                                                      provider->provider_baton,
-                                                     auth_baton->parameters,
+                                                     state->parameters,
                                                      state->realmstring,
                                                      auth_baton->pool));
         }
@@ -327,7 +370,9 @@ svn_auth_next_credentials(void **credent
       if (creds != NULL)
         {
           /* Put the creds in the cache */
-          svn_hash_sets(auth_baton->creds_cache, state->cache_key, creds);
+          svn_hash_sets(auth_baton->creds_cache,
+                        apr_pstrdup(auth_baton->pool, state->cache_key),
+                        creds);
           break;
         }
 
@@ -348,19 +393,17 @@ svn_auth_save_credentials(svn_auth_iters
   svn_auth_provider_object_t *provider;
   svn_boolean_t save_succeeded = FALSE;
   const char *no_auth_cache;
-  svn_auth_baton_t *auth_baton;
   void *creds;
 
   if (! state || state->table->providers->nelts <= state->provider_idx)
     return SVN_NO_ERROR;
 
-  auth_baton = state->auth_baton;
   creds = svn_hash_gets(state->auth_baton->creds_cache, state->cache_key);
   if (! creds)
     return SVN_NO_ERROR;
 
   /* Do not save the creds if SVN_AUTH_PARAM_NO_AUTH_CACHE is set */
-  no_auth_cache = svn_hash_gets(auth_baton->parameters,
+  no_auth_cache = svn_hash_gets(state->parameters,
                                 SVN_AUTH_PARAM_NO_AUTH_CACHE);
   if (no_auth_cache)
     return SVN_NO_ERROR;
@@ -373,7 +416,7 @@ svn_auth_save_credentials(svn_auth_iters
     SVN_ERR(provider->vtable->save_credentials(&save_succeeded,
                                                creds,
                                                provider->provider_baton,
-                                               auth_baton->parameters,
+                                               state->parameters,
                                                state->realmstring,
                                                pool));
   if (save_succeeded)
@@ -389,7 +432,7 @@ svn_auth_save_credentials(svn_auth_iters
       if (provider->vtable->save_credentials)
         SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
                                                    provider->provider_baton,
-                                                   auth_baton->parameters,
+                                                   state->parameters,
                                                    state->realmstring,
                                                    pool));
 
@@ -687,10 +730,12 @@ svn_auth_get_platform_specific_client_pr
 }
 
 svn_error_t *
-svn_auth__apply_config_for_server(svn_auth_baton_t *auth_baton,
-                                  apr_hash_t *config,
-                                  const char *server_name,
-                                  apr_pool_t *scratch_pool)
+svn_auth__make_session_auth(svn_auth_baton_t **session_auth_baton,
+                            const svn_auth_baton_t *auth_baton,
+                            apr_hash_t *config,
+                            const char *server_name,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
   svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
@@ -702,6 +747,12 @@ svn_auth__apply_config_for_server(svn_au
   svn_config_t *servers = NULL;
   const char *server_group = NULL;
 
+  struct svn_auth_baton_t *ab;
+
+  ab = apr_pmemdup(result_pool, auth_baton, sizeof(*ab));
+
+  ab->slave_parameters = apr_hash_make(result_pool);
+
   /* The 'store-passwords' and 'store-auth-creds' parameters used to
   * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
   * if values for these parameters have already been set by our
@@ -716,12 +767,10 @@ svn_auth__apply_config_for_server(svn_au
   * "store-auth-creds = yes" -- they'll get the expected behaviour.
   */
 
-  if (svn_auth_get_parameter(auth_baton,
-                              SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
+  if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
     store_passwords = FALSE;
 
-  if (svn_auth_get_parameter(auth_baton,
-                              SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
+  if (svn_auth_get_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
     store_auth_creds = FALSE;
 
   /* All the svn_auth_set_parameter() calls below this not only affect the
@@ -806,46 +855,60 @@ svn_auth__apply_config_for_server(svn_au
 
   /* Save auth caching parameters in the auth parameter hash. */
   if (! store_passwords)
-    svn_auth_set_parameter(auth_baton,
-                           SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
+    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
 
-  svn_auth_set_parameter(auth_baton,
+  svn_auth_set_parameter(ab,
                          SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
                          store_plaintext_passwords);
 
   if (! store_pp)
-    svn_auth_set_parameter(auth_baton,
+    svn_auth_set_parameter(ab,
                            SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
                            "");
 
-  svn_auth_set_parameter(auth_baton,
+  svn_auth_set_parameter(ab,
                          SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
                          store_pp_plaintext);
 
   if (! store_auth_creds)
-    svn_auth_set_parameter(auth_baton,
-                            SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
+    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
 
-  /* ### This setting may have huge side-effects when the auth baton is shared
-     ### between different ra sessions, as it will change which server settings
-     ### will be used for all future auth requests.
-     ###
-     ### E.g. when you connect using a ssl client cert that is specified in the
-     ### config file, you might have it when you first connect... but if you
-     ### then connect to another repository, you might not see the same
-     ### settings when the SSL connection is built up again later on.
-     ###
-     ### Most current usages should probably have been keyed on the realm
-     ### string instead of this magic flag that changes when multiple repositories
-     ### are used.
-     ###
-     ### This especially affects long living ra sessions, such as those on the
-     ### reuse-ra-session branch.
-   */
   if (server_group)
-    svn_auth_set_parameter(auth_baton,
+    svn_auth_set_parameter(ab,
                            SVN_AUTH_PARAM_SERVER_GROUP,
-                           apr_pstrdup(auth_baton->pool, server_group));
+                           apr_pstrdup(ab->pool, server_group));
+
+  *session_auth_baton = ab;
+
+  return SVN_NO_ERROR;
+}
+
 
+static svn_error_t *
+dummy_first_creds(void **credentials,
+                  void **iter_baton,
+                  void *provider_baton,
+                  apr_hash_t *parameters,
+                  const char *realmstring,
+                  apr_pool_t *pool)
+{
+  *credentials = NULL;
+  *iter_baton = NULL;
   return SVN_NO_ERROR;
 }
+
+void
+svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
+                                     apr_pool_t *pool)
+{
+  static const svn_auth_provider_t vtable = {
+    SVN_AUTH_CRED_SIMPLE,
+    dummy_first_creds,
+    NULL, NULL
+  };
+
+  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+  po->vtable = &vtable;
+  *provider = po;
+}

Modified: subversion/branches/ra-git/subversion/libsvn_subr/auth.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_subr/auth.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_subr/auth.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_subr/auth.h Mon Nov 30 10:24:16 2015
@@ -157,6 +157,15 @@ svn_auth__get_gpg_agent_simple_provider
      apr_pool_t *pool);
 #endif /* !defined(WIN32) || defined(DOXYGEN) */
 
+/**
+ * Set @a *provider to a dummy provider of type @c
+ * svn_auth_cred_simple_t that never returns or stores any
+ * credentials.
+ */
+void
+svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
+                                     apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */