You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by as...@apache.org on 2012/11/24 21:29:48 UTC

svn commit: r1413258 [13/33] - in /subversion/branches/compressed-pristines: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/ notes/ notes/directory-index/ subversion/ subv...

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/delta.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/delta.c Sat Nov 24 20:29:11 2012
@@ -629,12 +629,23 @@ svn_repos__compare_files(svn_boolean_t *
   if (!*changed_p)
     return SVN_NO_ERROR;
 
-  /* From this point on, assume things haven't changed. */
+  /* If the SHA1 checksums match for these things, we'll claim they
+     have the same contents.  (We don't give quite as much weight to
+     MD5 checksums.)  */
+  SVN_ERR(svn_fs_file_checksum(&checksum1, svn_checksum_sha1,
+                               root1, path1, FALSE, pool));
+  SVN_ERR(svn_fs_file_checksum(&checksum2, svn_checksum_sha1,
+                               root2, path2, FALSE, pool));
+  if (checksum1 && checksum2)
+    {
+      *changed_p = !svn_checksum_match(checksum1, checksum2);
+      return SVN_NO_ERROR;
+    }
+
+  /* From this point on, our default answer is "Nothing's changed". */
   *changed_p = FALSE;
 
-  /* So, things have changed.  But we need to know if the two sets of
-     file contents are actually different.  If they have differing
-     sizes, then we know they differ. */
+  /* Different filesizes means the contents are different. */
   SVN_ERR(svn_fs_file_length(&size1, root1, path1, pool));
   SVN_ERR(svn_fs_file_length(&size2, root2, path2, pool));
   if (size1 != size2)
@@ -643,8 +654,7 @@ svn_repos__compare_files(svn_boolean_t *
       return SVN_NO_ERROR;
     }
 
-  /* Same sizes, huh?  Well, if their checksums differ, we know they
-     differ. */
+  /* Different MD5 checksums means the contents are different. */
   SVN_ERR(svn_fs_file_checksum(&checksum1, svn_checksum_md5, root1, path1,
                                FALSE, pool));
   SVN_ERR(svn_fs_file_checksum(&checksum2, svn_checksum_md5, root2, path2,
@@ -655,13 +665,11 @@ svn_repos__compare_files(svn_boolean_t *
       return SVN_NO_ERROR;
     }
 
-  /* Same sizes, same checksums.  Chances are reallllly good that they
-     don't differ, but to be absolute sure, we need to compare bytes. */
+  /* And finally, different contents means the ... uh ... contents are
+     different. */
   SVN_ERR(svn_fs_file_contents(&stream1, root1, path1, pool));
   SVN_ERR(svn_fs_file_contents(&stream2, root2, path2, pool));
-
   SVN_ERR(svn_stream_contents_same2(&same, stream1, stream2, pool));
-
   *changed_p = !same;
 
   return SVN_NO_ERROR;

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/deprecated.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/deprecated.c Sat Nov 24 20:29:11 2012
@@ -48,8 +48,8 @@ svn_repos_get_commit_editor4(const svn_d
                              const char *base_path,
                              const char *user,
                              const char *log_msg,
-                             svn_commit_callback2_t callback,
-                             void *callback_baton,
+                             svn_commit_callback2_t commit_callback,
+                             void *commit_baton,
                              svn_repos_authz_callback_t authz_callback,
                              void *authz_baton,
                              apr_pool_t *pool)
@@ -65,7 +65,7 @@ svn_repos_get_commit_editor4(const svn_d
                  svn_string_create(log_msg, pool));
   return svn_repos_get_commit_editor5(editor, edit_baton, repos, txn,
                                       repos_url, base_path, revprop_table,
-                                      callback, callback_baton,
+                                      commit_callback, commit_baton,
                                       authz_callback, authz_baton, pool);
 }
 
@@ -254,6 +254,41 @@ svn_repos_begin_report(void **report_bat
 }
 
 svn_error_t *
+svn_repos_begin_report2(void **report_baton,
+                        svn_revnum_t revnum,
+                        svn_repos_t *repos,
+                        const char *fs_base,
+                        const char *target,
+                        const char *tgt_path,
+                        svn_boolean_t text_deltas,
+                        svn_depth_t depth,
+                        svn_boolean_t ignore_ancestry,
+                        svn_boolean_t send_copyfrom_args,
+                        const svn_delta_editor_t *editor,
+                        void *edit_baton,
+                        svn_repos_authz_func_t authz_read_func,
+                        void *authz_read_baton,
+                        apr_pool_t *pool)
+{
+  return svn_repos_begin_report3(report_baton,
+                                 revnum,
+                                 repos,
+                                 fs_base,
+                                 target,
+                                 tgt_path,
+                                 text_deltas,
+                                 depth,
+                                 ignore_ancestry,
+                                 send_copyfrom_args,
+                                 editor,
+                                 edit_baton,
+                                 authz_read_func,
+                                 authz_read_baton,
+                                 0,     /* disable zero-copy code path */
+                                 pool);
+}
+
+svn_error_t *
 svn_repos_set_path2(void *baton, const char *path, svn_revnum_t rev,
                     svn_boolean_t start_empty, const char *lock_token,
                     apr_pool_t *pool)

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/fs-wrap.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/fs-wrap.c Sat Nov 24 20:29:11 2012
@@ -31,10 +31,12 @@
 #include "svn_props.h"
 #include "svn_repos.h"
 #include "svn_time.h"
+#include "svn_sorts.h"
 #include "repos.h"
 #include "svn_private_config.h"
 #include "private/svn_repos_private.h"
 #include "private/svn_utf_private.h"
+#include "private/svn_fspath.h"
 
 
 /*** Commit wrappers ***/
@@ -48,6 +50,9 @@ svn_repos_fs_commit_txn(const char **con
 {
   svn_error_t *err, *err2;
   const char *txn_name;
+  apr_hash_t *props;
+  apr_pool_t *iterpool;
+  apr_hash_index_t *hi;
 
   *new_rev = SVN_INVALID_REVNUM;
 
@@ -55,6 +60,24 @@ svn_repos_fs_commit_txn(const char **con
   SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
   SVN_ERR(svn_repos__hooks_pre_commit(repos, txn_name, pool));
 
+  /* Remove any ephemeral transaction properties. */
+  SVN_ERR(svn_fs_txn_proplist(&props, txn, pool));
+  iterpool = svn_pool_create(pool);
+  for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      apr_hash_this(hi, &key, NULL, NULL);
+
+      svn_pool_clear(iterpool);
+
+      if (strncmp(key, SVN_PROP_TXN_PREFIX,
+                  (sizeof(SVN_PROP_TXN_PREFIX) - 1)) == 0)
+        {
+          SVN_ERR(svn_fs_change_txn_prop(txn, key, NULL, iterpool));
+        }
+    }
+  svn_pool_destroy(iterpool);
+  
   /* Commit. */
   err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
   if (! SVN_IS_VALID_REVNUM(*new_rev))
@@ -83,23 +106,29 @@ svn_repos_fs_begin_txn_for_commit2(svn_f
                                    apr_hash_t *revprop_table,
                                    apr_pool_t *pool)
 {
-  svn_string_t *author = apr_hash_get(revprop_table, SVN_PROP_REVISION_AUTHOR,
-                                      APR_HASH_KEY_STRING);
   apr_array_header_t *revprops;
+  const char *txn_name;
+  svn_string_t *author = apr_hash_get(revprop_table,
+                                      SVN_PROP_REVISION_AUTHOR,
+                                      APR_HASH_KEY_STRING);
 
-  /* Run start-commit hooks. */
-  SVN_ERR(svn_repos__hooks_start_commit(repos, author ? author->data : NULL,
-                                        repos->client_capabilities, pool));
-
-  /* Begin the transaction, ask for the fs to do on-the-fly lock checks. */
+  /* Begin the transaction, ask for the fs to do on-the-fly lock checks.
+     We fetch its name, too, so the start-commit hook can use it.  */
   SVN_ERR(svn_fs_begin_txn2(txn_p, repos->fs, rev,
                             SVN_FS_TXN_CHECK_LOCKS, pool));
+  SVN_ERR(svn_fs_txn_name(&txn_name, *txn_p, pool));
 
   /* We pass the revision properties to the filesystem by adding them
      as properties on the txn.  Later, when we commit the txn, these
      properties will be copied into the newly created revision. */
   revprops = svn_prop_hash_to_array(revprop_table, pool);
-  return svn_repos_fs_change_txn_props(*txn_p, revprops, pool);
+  SVN_ERR(svn_repos_fs_change_txn_props(*txn_p, revprops, pool));
+
+  /* Run start-commit hooks. */
+  SVN_ERR(svn_repos__hooks_start_commit(repos, author ? author->data : NULL,
+                                        repos->client_capabilities, txn_name,
+                                        pool));
+  return SVN_NO_ERROR;
 }
 
 
@@ -364,9 +393,9 @@ svn_repos_fs_revision_prop(svn_string_t 
     {
       /* Only svn:author and svn:date are fetchable. */
       if ((strncmp(propname, SVN_PROP_REVISION_AUTHOR,
-                   strlen(SVN_PROP_REVISION_AUTHOR)) != 0)
+                   sizeof(SVN_PROP_REVISION_AUTHOR)-1) != 0)
           && (strncmp(propname, SVN_PROP_REVISION_DATE,
-                      strlen(SVN_PROP_REVISION_DATE)) != 0))
+                      sizeof(SVN_PROP_REVISION_DATE)-1) != 0))
         *value_p = NULL;
 
       else
@@ -710,7 +739,54 @@ svn_repos_fs_pack2(svn_repos_t *repos,
                      cancel_func, cancel_baton, pool);
 }
 
+svn_error_t *
+svn_repos_fs_get_inherited_props(apr_array_header_t **inherited_props_p,
+                                 svn_fs_root_t *root,
+                                 const char *path,
+                                 svn_repos_authz_func_t authz_read_func,
+                                 void *authz_read_baton,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_array_header_t *inherited_props;
+  const char *parent_path = path;
+
+  inherited_props = apr_array_make(result_pool, 1,
+                                   sizeof(svn_prop_inherited_item_t *));
+  while (!(parent_path[0] == '/' && parent_path[1] == '\0'))
+    {
+      svn_boolean_t allowed = TRUE;
+      apr_hash_t *parent_properties;
+
+      svn_pool_clear(iterpool);
+      parent_path = svn_fspath__dirname(parent_path, scratch_pool);
+
+      if (authz_read_func)
+        SVN_ERR(authz_read_func(&allowed, root, parent_path,
+                                authz_read_baton, iterpool));
+      if (allowed)
+        {
+          SVN_ERR(svn_fs_node_proplist(&parent_properties, root,
+                                       parent_path, result_pool));
+          if (parent_properties && apr_hash_count(parent_properties))
+            {
+              svn_prop_inherited_item_t *i_props =
+                apr_pcalloc(result_pool, sizeof(*i_props));
+              i_props->path_or_url =
+                apr_pstrdup(result_pool, parent_path + 1);
+              i_props->prop_hash = parent_properties;
+              /* Build the output array in depth-first order. */
+              svn_sort__array_insert(&i_props, inherited_props, 0);
+            }
+        }
+    }
+
+  svn_pool_destroy(iterpool);
 
+  *inherited_props_p = inherited_props;
+  return SVN_NO_ERROR;
+}
 
 /*
  * vim:ts=4:sw=2:expandtab:tw=80:fo=tcroq

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/hooks.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/hooks.c Sat Nov 24 20:29:11 2012
@@ -215,6 +215,7 @@ run_hook_cmd(svn_string_t **result,
   svn_error_t *err;
   apr_proc_t cmd_proc = {0};
   apr_pool_t *cmd_pool;
+  apr_hash_t *hook_env = NULL;
 
   if (result)
     {
@@ -234,8 +235,19 @@ run_hook_cmd(svn_string_t **result,
    * destroy in order to clean up the stderr pipe opened for the process. */
   cmd_pool = svn_pool_create(pool);
 
+  /* Check if a custom environment is defined for this hook, or else
+   * whether a default environment is defined. */
+  if (hooks_env)
+    {
+      hook_env = apr_hash_get(hooks_env, name, APR_HASH_KEY_STRING);
+      if (hook_env == NULL)
+        hook_env = apr_hash_get(hooks_env,
+                                SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION,
+                                APR_HASH_KEY_STRING);
+    }
+    
   err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args,
-                          env_from_env_hash(hooks_env, pool, pool),
+                          env_from_env_hash(hook_env, pool, pool),
                           FALSE, FALSE, stdin_handle, result != NULL,
                           null_handle, TRUE, NULL, cmd_pool);
   if (!err)
@@ -357,6 +369,7 @@ svn_error_t *
 svn_repos__hooks_start_commit(svn_repos_t *repos,
                               const char *user,
                               const apr_array_header_t *capabilities,
+                              const char *txn_name,
                               apr_pool_t *pool)
 {
   const char *hook = svn_repos_start_commit_hook(repos, pool);
@@ -368,7 +381,7 @@ svn_repos__hooks_start_commit(svn_repos_
     }
   else if (hook)
     {
-      const char *args[5];
+      const char *args[6];
       char *capabilities_string;
 
       if (capabilities)
@@ -388,7 +401,8 @@ svn_repos__hooks_start_commit(svn_repos_
       args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool);
       args[2] = user ? user : "";
       args[3] = capabilities_string;
-      args[4] = NULL;
+      args[4] = txn_name;
+      args[5] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_START_COMMIT, hook, args,
                            repos->hooks_env, NULL, pool));

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/log.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/log.c Sat Nov 24 20:29:11 2012
@@ -39,6 +39,7 @@
 #include "repos.h"
 #include "private/svn_fspath.h"
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_subr_private.h"
 
 
 
@@ -159,6 +160,10 @@ svn_repos_check_revision_access(svn_repo
  * The CHANGED hash set and its keys and values are allocated in POOL;
  * keys are const char * paths and values are svn_log_changed_path_t.
  *
+ * To prevent changes from being processed over and over again, the
+ * changed paths for ROOT may be passed in PREFETCHED_CHANGES.  If the
+ * latter is NULL, we will request the list inside this function.
+ *
  * If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
  * AUTHZ_READ_BATON and FS) to check whether each changed-path (and
  * copyfrom_path) is readable:
@@ -177,18 +182,20 @@ static svn_error_t *
 detect_changed(apr_hash_t **changed,
                svn_fs_root_t *root,
                svn_fs_t *fs,
+               apr_hash_t *prefetched_changes,
                svn_repos_authz_func_t authz_read_func,
                void *authz_read_baton,
                apr_pool_t *pool)
 {
-  apr_hash_t *changes;
+  apr_hash_t *changes = prefetched_changes;
   apr_hash_index_t *hi;
   apr_pool_t *subpool;
   svn_boolean_t found_readable = FALSE;
   svn_boolean_t found_unreadable = FALSE;
 
-  *changed = apr_hash_make(pool);
-  SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+  *changed = svn_hash__make(pool);
+  if (changes == NULL)
+    SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
 
   if (apr_hash_count(changes) == 0)
     /* No paths changed in this revision?  Uh, sure, I guess the
@@ -551,26 +558,28 @@ next_history_rev(const apr_array_header_
 
 /* Set *DELETED_MERGEINFO_CATALOG and *ADDED_MERGEINFO_CATALOG to
    catalogs describing how mergeinfo values on paths (which are the
-   keys of those catalogs) were changed in REV. */
+   keys of those catalogs) were changed in REV.  If *PREFETCHED_CAHNGES
+   already contains the changed paths for REV, use that.  Otherwise,
+   request that data and return it in *PREFETCHED_CHANGES. */
 /* ### TODO: This would make a *great*, useful public function,
    ### svn_repos_fs_mergeinfo_changed()!  -- cmpilato  */
 static svn_error_t *
 fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog,
                      svn_mergeinfo_catalog_t *added_mergeinfo_catalog,
+                     apr_hash_t **prefetched_changes,
                      svn_fs_t *fs,
                      svn_revnum_t rev,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 
 {
-  apr_hash_t *changes;
   svn_fs_root_t *root;
   apr_pool_t *iterpool;
   apr_hash_index_t *hi;
 
   /* Initialize return variables. */
-  *deleted_mergeinfo_catalog = apr_hash_make(result_pool);
-  *added_mergeinfo_catalog = apr_hash_make(result_pool);
+  *deleted_mergeinfo_catalog = svn_hash__make(result_pool);
+  *added_mergeinfo_catalog = svn_hash__make(result_pool);
 
   /* Revision 0 has no mergeinfo and no mergeinfo changes. */
   if (rev == 0)
@@ -579,17 +588,20 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
   /* We're going to use the changed-paths information for REV to
      narrow down our search. */
   SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
-  SVN_ERR(svn_fs_paths_changed2(&changes, root, scratch_pool));
+  if (*prefetched_changes == NULL)
+    SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
 
   /* No changed paths?  We're done. */
-  if (apr_hash_count(changes) == 0)
+  if (apr_hash_count(*prefetched_changes) == 0)
     return SVN_NO_ERROR;
 
   /* Loop over changes, looking for anything that might carry an
      svn:mergeinfo change and is one of our paths of interest, or a
      child or [grand]parent directory thereof. */
   iterpool = svn_pool_create(scratch_pool);
-  for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(scratch_pool, *prefetched_changes); 
+       hi;
+       hi = apr_hash_next(hi))
     {
       const void *key;
       void *val;
@@ -769,10 +781,14 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
 /* Determine what (if any) mergeinfo for PATHS was modified in
    revision REV, returning the differences for added mergeinfo in
    *ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
+   If *PREFETCHED_CAHNGES already contains the changed paths for
+   REV, use that.  Otherwise, request that data and return it in
+   *PREFETCHED_CHANGES.
    Use POOL for all allocations. */
 static svn_error_t *
 get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
                                svn_mergeinfo_t *deleted_mergeinfo,
+                               apr_hash_t **prefetched_changes,
                                svn_fs_t *fs,
                                const apr_array_header_t *paths,
                                svn_revnum_t rev,
@@ -787,8 +803,8 @@ get_combined_mergeinfo_changes(svn_merge
   svn_error_t *err;
 
   /* Initialize return value. */
-  *added_mergeinfo = apr_hash_make(result_pool);
-  *deleted_mergeinfo = apr_hash_make(result_pool);
+  *added_mergeinfo = svn_hash__make(result_pool);
+  *deleted_mergeinfo = svn_hash__make(result_pool);
 
   /* If we're asking about revision 0, there's no mergeinfo to be found. */
   if (rev == 0)
@@ -804,6 +820,7 @@ get_combined_mergeinfo_changes(svn_merge
   /* Fetch the mergeinfo changes for REV. */
   err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
                              &added_mergeinfo_catalog,
+                             prefetched_changes,
                              fs, rev, scratch_pool, scratch_pool);
   if (err)
     {
@@ -829,6 +846,7 @@ get_combined_mergeinfo_changes(svn_merge
     {
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
       const char *prev_path;
+      apr_ssize_t klen;
       svn_revnum_t appeared_rev, prev_rev;
       svn_fs_root_t *prev_root;
       svn_mergeinfo_catalog_t catalog, inherited_catalog;
@@ -899,8 +917,9 @@ get_combined_mergeinfo_changes(svn_merge
                                     FALSE, /* adjust_inherited_mergeinfo */
                                     iterpool, iterpool));
 
-      prev_mergeinfo = apr_hash_get(catalog, prev_path, APR_HASH_KEY_STRING);
-      prev_inherited_mergeinfo = apr_hash_get(inherited_catalog, prev_path, APR_HASH_KEY_STRING);
+      klen = strlen(prev_path);
+      prev_mergeinfo = apr_hash_get(catalog, prev_path, klen);
+      prev_inherited_mergeinfo = apr_hash_get(inherited_catalog, prev_path, klen);
 
       /* Fetch the current mergeinfo (as of REV, and including
          inherited stuff) for this path. */
@@ -915,8 +934,9 @@ get_combined_mergeinfo_changes(svn_merge
                                     FALSE, /* adjust_inherited_mergeinfo */
                                     iterpool, iterpool));
 
-      mergeinfo = apr_hash_get(catalog, path, APR_HASH_KEY_STRING);
-      inherited_mergeinfo = apr_hash_get(inherited_catalog, path, APR_HASH_KEY_STRING);
+      klen = strlen(path);
+      mergeinfo = apr_hash_get(catalog, path, klen);
+      inherited_mergeinfo = apr_hash_get(inherited_catalog, path, klen);
 
       if (!prev_mergeinfo && !mergeinfo)
         continue;
@@ -935,6 +955,16 @@ get_combined_mergeinfo_changes(svn_merge
           if (inherits_same_mergeinfo)
             continue;
         }
+      else
+        {
+          svn_boolean_t same_mergeinfo;
+          SVN_ERR(svn_mergeinfo__equals(&same_mergeinfo,
+                                        prev_inherited_mergeinfo,
+                                        FALSE,
+                                        TRUE, iterpool));
+          if (same_mergeinfo)
+            continue;
+        }
 
       /* Compare, constrast, and combine the results. */
       SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, prev_mergeinfo,
@@ -989,6 +1019,7 @@ static svn_error_t *
 fill_log_entry(svn_log_entry_t *log_entry,
                svn_revnum_t rev,
                svn_fs_t *fs,
+               apr_hash_t *prefetched_changes,
                svn_boolean_t discover_changed_paths,
                const apr_array_header_t *revprops,
                svn_repos_authz_func_t authz_read_func,
@@ -1008,7 +1039,7 @@ fill_log_entry(svn_log_entry_t *log_entr
 
       SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
       patherr = detect_changed(&changed_paths,
-                               newroot, fs,
+                               newroot, fs, prefetched_changes,
                                authz_read_func, authz_read_baton,
                                pool);
 
@@ -1048,7 +1079,7 @@ fill_log_entry(svn_log_entry_t *log_entr
           if (censor_revprops)
             {
               /* ... but we can only return author/date. */
-              log_entry->revprops = apr_hash_make(pool);
+              log_entry->revprops = svn_hash__make(pool);
               apr_hash_set(log_entry->revprops, SVN_PROP_REVISION_AUTHOR,
                            APR_HASH_KEY_STRING,
                            apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR,
@@ -1077,7 +1108,7 @@ fill_log_entry(svn_log_entry_t *log_entr
                 /* ... but we can only return author/date. */
                 continue;
               if (log_entry->revprops == NULL)
-                log_entry->revprops = apr_hash_make(pool);
+                log_entry->revprops = svn_hash__make(pool);
               apr_hash_set(log_entry->revprops, name,
                            APR_HASH_KEY_STRING, value);
             }
@@ -1119,6 +1150,7 @@ fill_log_entry(svn_log_entry_t *log_entr
 static svn_error_t *
 send_log(svn_revnum_t rev,
          svn_fs_t *fs,
+         apr_hash_t *prefetched_changes,
          svn_mergeinfo_t log_target_history_as_mergeinfo,
          apr_hash_t *nested_merges,
          svn_boolean_t discover_changed_paths,
@@ -1137,7 +1169,7 @@ send_log(svn_revnum_t rev,
   svn_boolean_t found_rev_of_interest = TRUE;
 
   log_entry = svn_log_entry_create(pool);
-  SVN_ERR(fill_log_entry(log_entry, rev, fs,
+  SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
                          discover_changed_paths || handling_merged_revision,
                          revprops, authz_read_func, authz_read_baton,
                          pool));
@@ -1800,7 +1832,7 @@ store_search(svn_mergeinfo_t processed,
      singe revisions where HIST_START is equal to HIST_END. */
   svn_revnum_t start = hist_start <= hist_end ? hist_start : hist_end;
   svn_revnum_t end = hist_start <= hist_end ? hist_end + 1 : hist_start + 1;
-  svn_mergeinfo_t mergeinfo = apr_hash_make(scratch_pool);
+  svn_mergeinfo_t mergeinfo = svn_hash__make(scratch_pool);
   apr_pool_t *processed_pool = apr_hash_pool_get(processed);
   int i;
 
@@ -1941,6 +1973,7 @@ do_logs(svn_fs_t *fs,
           svn_mergeinfo_t added_mergeinfo = NULL;
           svn_mergeinfo_t deleted_mergeinfo = NULL;
           svn_boolean_t has_children = FALSE;
+          apr_hash_t *changes = NULL;
 
           /* If we're including merged revisions, we need to calculate
              the mergeinfo deltas committed in this revision to our
@@ -1961,6 +1994,7 @@ do_logs(svn_fs_t *fs,
                 }
               SVN_ERR(get_combined_mergeinfo_changes(&added_mergeinfo,
                                                      &deleted_mergeinfo,
+                                                     &changes,
                                                      fs, cur_paths,
                                                      current, iterpool,
                                                      iterpool));
@@ -1973,7 +2007,7 @@ do_logs(svn_fs_t *fs,
              in anyway). */
           if (descending_order)
             {
-              SVN_ERR(send_log(current, fs,
+              SVN_ERR(send_log(current, fs, changes,
                                log_target_history_as_mergeinfo, nested_merges,
                                discover_changed_paths,
                                subtractive_merge, handling_merged_revisions,
@@ -1989,8 +2023,8 @@ do_logs(svn_fs_t *fs,
                          single hash to be shared across all of the merged
                          recursions so we can track and squelch duplicates. */
                       subpool = svn_pool_create(pool);
-                      nested_merges = apr_hash_make(subpool);
-                      processed = apr_hash_make(subpool);
+                      nested_merges = svn_hash__make(subpool);
+                      processed = svn_hash__make(subpool);
                     }
 
                   SVN_ERR(handle_merged_revisions(
@@ -2035,7 +2069,7 @@ do_logs(svn_fs_t *fs,
 
                   *cur_rev = current;
                   if (! rev_mergeinfo)
-                    rev_mergeinfo = apr_hash_make(pool);
+                    rev_mergeinfo = svn_hash__make(pool);
                   apr_hash_set(rev_mergeinfo, cur_rev, sizeof(*cur_rev),
                                add_and_del_mergeinfo);
                 }
@@ -2078,8 +2112,8 @@ do_logs(svn_fs_t *fs,
                               || apr_hash_count(deleted_mergeinfo) > 0);
             }
 
-          SVN_ERR(send_log(current, fs, log_target_history_as_mergeinfo,
-                           nested_merges,
+          SVN_ERR(send_log(current, fs, NULL,
+                           log_target_history_as_mergeinfo, nested_merges,
                            discover_changed_paths, subtractive_merge,
                            handling_merged_revisions, revprops, has_children,
                            receiver, receiver_baton, authz_read_func,
@@ -2089,7 +2123,7 @@ do_logs(svn_fs_t *fs,
               if (!nested_merges)
                 {
                   subpool = svn_pool_create(pool);
-                  nested_merges = apr_hash_make(subpool);
+                  nested_merges = svn_hash__make(subpool);
                 }
 
               SVN_ERR(handle_merged_revisions(current, fs,
@@ -2169,7 +2203,7 @@ get_paths_history_as_mergeinfo(svn_merge
       end_rev = tmp_rev;
     }
 
-  *paths_history_mergeinfo = apr_hash_make(result_pool);
+  *paths_history_mergeinfo = svn_hash__make(result_pool);
 
   for (i = 0; i < paths->nelts; i++)
     {
@@ -2302,7 +2336,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
             rev = end - i;
           else
             rev = start + i;
-          SVN_ERR(send_log(rev, fs, NULL, NULL, discover_changed_paths, FALSE,
+          SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
+                           discover_changed_paths, FALSE,
                            FALSE, revprops, FALSE, receiver,
                            receiver_baton, authz_read_func,
                            authz_read_baton, iterpool));

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/replay.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/replay.c Sat Nov 24 20:29:11 2012
@@ -150,7 +150,6 @@ struct path_driver_cb_baton
   apr_pool_t *pool;
 };
 
-#ifndef USE_EV2_IMPL
 /* Recursively traverse EDIT_PATH (as it exists under SOURCE_ROOT) emitting
    the appropriate editor calls to add it and its children without any
    history.  This is meant to be used when either a subset of the tree
@@ -342,7 +341,6 @@ add_subdir(svn_fs_root_t *source_root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 /* Given PATH deleted under ROOT, return in READABLE whether the path was
    readable prior to the deletion.  Consult COPIES (a stack of 'struct
@@ -459,7 +457,6 @@ fill_copyfrom(svn_fs_root_t **copyfrom_r
   return SVN_NO_ERROR;
 }
 
-#ifndef USE_EV2_IMPL
 static svn_error_t *
 path_driver_cb_func(void **dir_baton,
                     void *parent_baton,
@@ -784,8 +781,7 @@ path_driver_cb_func(void **dir_baton,
   return SVN_NO_ERROR;
 }
 
-#else
-
+#ifdef USE_EV2_IMPL
 static svn_error_t *
 fetch_kind_func(svn_kind_t *kind,
                 void *baton,
@@ -795,8 +791,14 @@ fetch_kind_func(svn_kind_t *kind,
 {
   svn_fs_root_t *root = baton;
   svn_node_kind_t node_kind;
+  svn_fs_root_t *prev_root;
+  svn_fs_t *fs = svn_fs_root_fs(root);
 
-  SVN_ERR(svn_fs_check_path(&node_kind, root, path, scratch_pool));
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = svn_fs_revision_root_revision(root) - 1;
+
+  SVN_ERR(svn_fs_revision_root(&prev_root, fs, base_revision, scratch_pool));
+  SVN_ERR(svn_fs_check_path(&node_kind, prev_root, path, scratch_pool));
 
   *kind = svn__kind_from_node_kind(node_kind, FALSE);
   return SVN_NO_ERROR;
@@ -814,15 +816,14 @@ fetch_props_func(apr_hash_t **props,
   svn_fs_root_t *prev_root;
   svn_fs_t *fs = svn_fs_root_fs(root);
 
-  SVN_ERR(svn_fs_revision_root(&prev_root, fs,
-                               svn_fs_revision_root_revision(root) - 1,
-                               scratch_pool));
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = svn_fs_revision_root_revision(root) - 1;
 
+  SVN_ERR(svn_fs_revision_root(&prev_root, fs, base_revision, scratch_pool));
   SVN_ERR(svn_fs_node_proplist(props, prev_root, path, result_pool));
 
   return SVN_NO_ERROR;
 }
-
 #endif
 
 
@@ -947,9 +948,9 @@ svn_repos_replay2(svn_fs_root_t *root,
     }
 
   /* Call the path-based editor driver. */
-  return svn_delta_path_driver(editor, edit_baton,
-                               SVN_INVALID_REVNUM, paths,
-                               path_driver_cb_func, &cb_baton, pool);
+  return svn_delta_path_driver2(editor, edit_baton,
+                                paths, TRUE,
+                                path_driver_cb_func, &cb_baton, pool);
 #else
   svn_editor_t *editorv2;
   struct svn_delta__extra_baton *exb;
@@ -1009,7 +1010,6 @@ svn_repos_replay2(svn_fs_root_t *root,
  *                      Ev2 Implementation                       *
  *****************************************************************/
 
-#ifdef USE_EV2_IMPL
 /* Recursively traverse EDIT_PATH (as it exists under SOURCE_ROOT) emitting
    the appropriate editor calls to add it and its children without any
    history.  This is meant to be used when either a subset of the tree
@@ -1018,16 +1018,16 @@ svn_repos_replay2(svn_fs_root_t *root,
    unavailable because of authz and we need to use it as the source of
    a copy. */
 static svn_error_t *
-add_subdir(svn_fs_root_t *source_root,
-           svn_fs_root_t *target_root,
-           svn_editor_t *editor,
-           const char *repos_relpath,
-           const char *source_fspath,
-           svn_repos_authz_func_t authz_read_func,
-           void *authz_read_baton,
-           apr_hash_t *changed_paths,
-           apr_pool_t *result_pool,
-           apr_pool_t *scratch_pool)
+add_subdir_ev2(svn_fs_root_t *source_root,
+               svn_fs_root_t *target_root,
+               svn_editor_t *editor,
+               const char *repos_relpath,
+               const char *source_fspath,
+               svn_repos_authz_func_t authz_read_func,
+               void *authz_read_baton,
+               apr_hash_t *changed_paths,
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_hash_index_t *hi;
@@ -1131,11 +1131,11 @@ add_subdir(svn_fs_root_t *source_root,
             }
           else
             {
-              SVN_ERR(add_subdir(new_source_root, target_root,
-                                 editor, child_relpath,
-                                 new_source_fspath,
-                                 authz_read_func, authz_read_baton,
-                                 changed_paths, result_pool, iterpool));
+              SVN_ERR(add_subdir_ev2(new_source_root, target_root,
+                                     editor, child_relpath,
+                                     new_source_fspath,
+                                     authz_read_func, authz_read_baton,
+                                     changed_paths, result_pool, iterpool));
             }
         }
       else if (dent->kind == svn_node_file)
@@ -1164,7 +1164,6 @@ add_subdir(svn_fs_root_t *source_root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 static svn_error_t *
 replay_node(svn_fs_root_t *root,
@@ -1178,11 +1177,6 @@ replay_node(svn_fs_root_t *root,
             void *authz_read_baton,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
-#ifndef USE_EV2_IMPL
-{
-  SVN__NOT_IMPLEMENTED();
-}
-#else
 {
   svn_fs_path_change2_t *change;
   svn_boolean_t do_add = FALSE;
@@ -1297,10 +1291,11 @@ replay_node(svn_fs_root_t *root,
              contents. */
           if (change->copyfrom_path && ! copyfrom_path)
             {
-              SVN_ERR(add_subdir(copyfrom_root, root, editor,
-                                 repos_relpath, change->copyfrom_path,
-                                 authz_read_func, authz_read_baton,
-                                 changed_paths, result_pool, scratch_pool));
+              SVN_ERR(add_subdir_ev2(copyfrom_root, root, editor,
+                                     repos_relpath, change->copyfrom_path,
+                                     authz_read_func, authz_read_baton,
+                                     changed_paths, result_pool,
+                                     scratch_pool));
             }
           else
             {
@@ -1437,15 +1432,18 @@ replay_node(svn_fs_root_t *root,
       if (change->node_kind == svn_node_file
           && (change->text_mod || change->prop_mod || downgraded_copy))
         {
-          svn_checksum_t *checksum;
-          svn_stream_t *contents;
+          svn_checksum_t *checksum = NULL;
+          svn_stream_t *contents = NULL;
 
-          SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
-                                       root, repos_relpath, TRUE,
-                                       scratch_pool));
+          if (change->text_mod)
+            {
+              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
+                                           root, repos_relpath, TRUE,
+                                           scratch_pool));
 
-          SVN_ERR(svn_fs_file_contents(&contents, root, repos_relpath,
-                                       scratch_pool));
+              SVN_ERR(svn_fs_file_contents(&contents, root, repos_relpath,
+                                           scratch_pool));
+            }
 
           SVN_ERR(svn_editor_alter_file(editor, repos_relpath,
                                         SVN_INVALID_REVNUM, props, checksum,
@@ -1465,7 +1463,6 @@ replay_node(svn_fs_root_t *root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 svn_error_t *
 svn_repos__replay_ev2(svn_fs_root_t *root,

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/reporter.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/reporter.c Sat Nov 24 20:29:11 2012
@@ -36,6 +36,7 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_string_private.h"
 
 #define NUM_CACHED_SOURCE_ROOTS 4
 
@@ -102,13 +103,15 @@ typedef struct revision_info_t
    driven by the client as it describes its working copy revisions. */
 typedef struct report_baton_t
 {
-  /* Parameters remembered from svn_repos_begin_report2 */
+  /* Parameters remembered from svn_repos_begin_report3 */
   svn_repos_t *repos;
   const char *fs_base;         /* fspath corresponding to wc anchor */
   const char *s_operand;       /* anchor-relative wc target (may be empty) */
   svn_revnum_t t_rev;          /* Revnum which the edit will bring the wc to */
   const char *t_path;          /* FS path the edit will bring the wc to */
   svn_boolean_t text_deltas;   /* Whether to report text deltas */
+  apr_size_t zero_copy_limit;  /* Max item size that will be sent using
+                                  the zero-copy code path. */
 
   /* If the client requested a specific depth, record it here; if the
      client did not, then this is svn_depth_unknown, and the depth of
@@ -135,8 +138,10 @@ typedef struct report_baton_t
 
   /* Cache for revision properties. This is used to eliminate redundant
      revprop fetching. */
-  apr_hash_t* revision_infos;
+  apr_hash_t *revision_infos;
 
+  /* This will not change. So, fetch it once and reuse it. */
+  svn_string_t *repos_uuid;
   apr_pool_t *pool;
 } report_baton_t;
 
@@ -513,25 +518,29 @@ delta_proplists(report_baton_t *b, svn_r
                 void *object, apr_pool_t *pool)
 {
   svn_fs_root_t *s_root;
-  apr_hash_t *s_props, *t_props;
+  apr_hash_t *s_props = NULL, *t_props;
   apr_array_header_t *prop_diffs;
   int i;
   svn_revnum_t crev;
-  const char *uuid;
-  svn_string_t *cr_str;
-  revision_info_t* revision_info;
+  revision_info_t *revision_info;
   svn_boolean_t changed;
   const svn_prop_t *pc;
   svn_lock_t *lock;
+  apr_hash_index_t *hi;
 
   /* Fetch the created-rev and send entry props. */
   SVN_ERR(svn_fs_node_created_rev(&crev, b->t_root, t_path, pool));
   if (SVN_IS_VALID_REVNUM(crev))
     {
+      /* convert committed-rev to  string */
+      char buf[SVN_INT64_BUFFER_SIZE];
+      svn_string_t cr_str;
+      cr_str.data = buf;
+      cr_str.len = svn__i64toa(buf, crev);
+
       /* Transmit the committed-rev. */
-      cr_str = svn_string_createf(pool, "%ld", crev);
       SVN_ERR(change_fn(b, object,
-                        SVN_PROP_ENTRY_COMMITTED_REV, cr_str, pool));
+                        SVN_PROP_ENTRY_COMMITTED_REV, &cr_str, pool));
 
       SVN_ERR(get_revision_info(b, crev, &revision_info, pool));
 
@@ -546,9 +555,8 @@ delta_proplists(report_baton_t *b, svn_r
                           revision_info->author, pool));
 
       /* Transmit the UUID. */
-      SVN_ERR(svn_fs_get_uuid(b->repos->fs, &uuid, pool));
       SVN_ERR(change_fn(b, object, SVN_PROP_ENTRY_UUID,
-                        svn_string_create(uuid, pool), pool));
+                        b->repos_uuid, pool));
     }
 
   /* Update lock properties. */
@@ -575,23 +583,83 @@ delta_proplists(report_baton_t *b, svn_r
       /* If so, go ahead and get the source path's properties. */
       SVN_ERR(svn_fs_node_proplist(&s_props, s_root, s_path, pool));
     }
-  else
-    s_props = apr_hash_make(pool);
 
   /* Get the target path's properties */
   SVN_ERR(svn_fs_node_proplist(&t_props, b->t_root, t_path, pool));
 
-  /* Now transmit the differences. */
-  SVN_ERR(svn_prop_diffs(&prop_diffs, t_props, s_props, pool));
-  for (i = 0; i < prop_diffs->nelts; i++)
+  if (s_props && apr_hash_count(s_props))
+    {
+      /* Now transmit the differences. */
+      SVN_ERR(svn_prop_diffs(&prop_diffs, t_props, s_props, pool));
+      for (i = 0; i < prop_diffs->nelts; i++)
+        {
+          pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
+          SVN_ERR(change_fn(b, object, pc->name, pc->value, pool));
+        }
+    }
+  else if (apr_hash_count(t_props))
+    {
+      /* So source, i.e. all new.  Transmit all target props. */
+      for (hi = apr_hash_first(pool, t_props); hi; hi = apr_hash_next(hi))
+        {
+          const void *key;
+          void *val;
+
+          apr_hash_this(hi, &key, NULL, &val);
+          SVN_ERR(change_fn(b, object, key, val, pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Baton type to be passed into send_zero_copy_delta.
+ */
+typedef struct zero_copy_baton_t
+{
+  /* don't process data larger than this limit */
+  apr_size_t zero_copy_limit;
+
+  /* window handler and baton to send the data to */
+  svn_txdelta_window_handler_t dhandler;
+  void *dbaton;
+
+  /* return value: will be set to TRUE, if the data was processed. */
+  svn_boolean_t zero_copy_succeeded;
+} zero_copy_baton_t;
+
+/* Implement svn_fs_process_contents_func_t.  If LEN is smaller than the
+ * limit given in *BATON, send the CONTENTS as an delta windows to the
+ * handler given in BATON and set the ZERO_COPY_SUCCEEDED flag in that
+ * BATON.  Otherwise, reset it to FALSE.
+ * Use POOL for temporary allocations.
+ */
+static svn_error_t *
+send_zero_copy_delta(const unsigned char *contents,
+                     apr_size_t len,
+                     void *baton,
+                     apr_pool_t *pool)
+{
+  zero_copy_baton_t *zero_copy_baton = baton;
+
+  /* if the item is too large, the caller must revert to traditional
+     streaming code. */
+  if (len > zero_copy_baton->zero_copy_limit)
     {
-      pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
-      SVN_ERR(change_fn(b, object, pc->name, pc->value, pool));
+      zero_copy_baton->zero_copy_succeeded = FALSE;
+      return SVN_NO_ERROR;
     }
 
+  SVN_ERR(svn_txdelta_send_contents(contents, len,
+                                    zero_copy_baton->dhandler,
+                                    zero_copy_baton->dbaton, pool));
+
+  /* all fine now */
+  zero_copy_baton->zero_copy_succeeded = TRUE;
   return SVN_NO_ERROR;
 }
 
+
 /* Make the appropriate edits on FILE_BATON to change its contents and
    properties from those in S_REV/S_PATH to those in B->t_root/T_PATH,
    possibly using LOCK_TOKEN to determine if the client's lock on the file
@@ -645,6 +713,26 @@ delta_files(report_baton_t *b, void *fil
     {
       if (b->text_deltas)
         {
+          /* if we send deltas against empty streams, we may use our
+             zero-copy code. */
+          if (b->zero_copy_limit > 0 && s_path == NULL)
+            {
+              zero_copy_baton_t baton = { b->zero_copy_limit
+                                        , dhandler
+                                        , dbaton
+                                        , FALSE};
+              svn_boolean_t called = FALSE;
+              SVN_ERR(svn_fs_try_process_file_contents(&called,
+                                                       b->t_root, t_path,
+                                                       send_zero_copy_delta,
+                                                       &baton, pool));
+
+              /* data has been available and small enough,
+                 i.e. been processed? */
+              if (called && baton.zero_copy_succeeded)
+                return SVN_NO_ERROR;
+            }
+
           SVN_ERR(svn_fs_get_file_delta_stream(&dstream, s_root, s_path,
                                                b->t_root, t_path, pool));
           SVN_ERR(svn_txdelta_send_txstream(dstream, dhandler, dbaton, pool));
@@ -1463,7 +1551,7 @@ svn_repos_abort_report(void *baton, apr_
 
 
 svn_error_t *
-svn_repos_begin_report2(void **report_baton,
+svn_repos_begin_report3(void **report_baton,
                         svn_revnum_t revnum,
                         svn_repos_t *repos,
                         const char *fs_base,
@@ -1477,14 +1565,18 @@ svn_repos_begin_report2(void **report_ba
                         void *edit_baton,
                         svn_repos_authz_func_t authz_read_func,
                         void *authz_read_baton,
+                        apr_size_t zero_copy_limit,
                         apr_pool_t *pool)
 {
   report_baton_t *b;
+  const char *uuid;
 
   if (depth == svn_depth_exclude)
     return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("Request depth 'exclude' not supported"));
 
+  SVN_ERR(svn_fs_get_uuid(repos->fs, &uuid, pool));
+
   /* Build a reporter baton.  Copy strings in case the caller doesn't
      keep track of them. */
   b = apr_palloc(pool, sizeof(*b));
@@ -1495,6 +1587,7 @@ svn_repos_begin_report2(void **report_ba
   b->t_path = switch_path ? svn_fspath__canonicalize(switch_path, pool)
                           : svn_fspath__join(b->fs_base, s_operand, pool);
   b->text_deltas = text_deltas;
+  b->zero_copy_limit = zero_copy_limit;
   b->requested_depth = depth;
   b->ignore_ancestry = ignore_ancestry;
   b->send_copyfrom_args = send_copyfrom_args;
@@ -1508,6 +1601,7 @@ svn_repos_begin_report2(void **report_ba
   b->reader = svn_spillbuf__reader_create(1000 /* blocksize */,
                                           1000000 /* maxsize */,
                                           pool);
+  b->repos_uuid = svn_string_create(uuid, pool);
 
   /* Hand reporter back to client. */
   *report_baton = b;

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.c Sat Nov 24 20:29:11 2012
@@ -34,6 +34,7 @@
 #include "svn_repos.h"
 #include "svn_hash.h"
 #include "svn_version.h"
+#include "svn_config.h"
 
 #include "private/svn_repos_private.h"
 #include "private/svn_subr_private.h"
@@ -166,13 +167,6 @@ svn_repos_post_revprop_change_hook(svn_r
                        pool);
 }
 
-void
-svn_repos_hooks_setenv(svn_repos_t *repos,
-                       apr_hash_t *hooks_env)
-{
-  repos->hooks_env = hooks_env;
-}
-
 static svn_error_t *
 create_repos_dir(const char *path, apr_pool_t *pool)
 {
@@ -311,16 +305,17 @@ create_hooks(svn_repos_t *repos, apr_poo
 ""                                                                           NL
 "# START-COMMIT HOOK"                                                        NL
 "#"                                                                          NL
-"# The start-commit hook is invoked before a Subversion txn is created"      NL
-"# in the process of doing a commit.  Subversion runs this hook"             NL
-"# by invoking a program (script, executable, binary, etc.) named"           NL
-"# '"SCRIPT_NAME"' (for which this file is a template)"                      NL
-"# with the following ordered arguments:"                                    NL
+"# The start-commit hook is invoked immediately after a Subversion txn is"   NL
+"# created and populated with initial revprops in the process of doing a"    NL
+"# commit. Subversion runs this hook by invoking a program (script, "        NL
+"# executable, binary, etc.) named '"SCRIPT_NAME"' (for which this file"     NL
+"# is a template) with the following ordered arguments:"                     NL
 "#"                                                                          NL
 "#   [1] REPOS-PATH   (the path to this repository)"                         NL
 "#   [2] USER         (the authenticated user attempting to commit)"         NL
 "#   [3] CAPABILITIES (a colon-separated list of capabilities reported"      NL
 "#                     by the client; see note below)"                       NL
+"#   [4] TXN-NAME     (the name of the commit txn just created)"             NL
 "#"                                                                          NL
 "# Note: The CAPABILITIES parameter is new in Subversion 1.5, and 1.5"       NL
 "# clients will typically report at least the \""                            \
@@ -329,6 +324,11 @@ create_hooks(svn_repos_t *repos, apr_poo
 "# e.g.: \"" SVN_RA_CAPABILITY_MERGEINFO ":some-other-capability\" "         \
   "(the order is undefined)."                                                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
@@ -1035,6 +1035,13 @@ create_conf(svn_repos_t *repos, apr_pool
 "### \"none\" (to compare usernames as-is without case conversion, which"    NL
 "### is the default behavior)."                                              NL
 "# force-username-case = none"                                               NL
+"### The hooks-env options specifies a path to the hook script environment " NL
+"### configuration file. This option overrides the per-repository default"   NL
+"### and can be used to configure the hook script environment for multiple " NL
+"### repositories in a single file, if an absolute path is specified."       NL
+"### Unless you specify an absolute path, the file's location is relative"   NL
+"### to the directory containing this file."                                 NL
+"# hooks-env = " SVN_REPOS__CONF_HOOKS_ENV                                   NL
 ""                                                                           NL
 "[sasl]"                                                                     NL
 "### This option specifies whether you want to use the Cyrus SASL"           NL
@@ -1049,17 +1056,7 @@ create_conf(svn_repos_t *repos, apr_pool
 "### to the effective key length for encryption (e.g. 128 means 128-bit"     NL
 "### encryption). The values below are the defaults."                        NL
 "# min-encryption = 0"                                                       NL
-"# max-encryption = 256"                                                     NL
-""                                                                           NL
-"[hooks-env]"                                                                NL
-"### Options in this section define environment variables for use by"        NL
-"### hook scripts run by svnserve."                                          NL
-#ifdef WIN32
-"# PATH = C:\\Program Files\\Subversion\\bin"                                NL
-#else
-"# PATH = /bin:/sbin:/usr/bin:/usr/sbin"                                     NL
-#endif
-"# LC_CTYPE = en_US.UTF-8"                                                   NL;
+"# max-encryption = 256"                                                     NL;
 
     SVN_ERR_W(svn_io_file_create(svn_repos_svnserve_conf(repos, pool),
                                  svnserve_conf_contents, pool),
@@ -1126,6 +1123,129 @@ create_conf(svn_repos_t *repos, apr_pool
               _("Creating authz file"));
   }
 
+  {
+    static const char * const hooks_env_contents =
+"### This file is an example hook script environment configuration file."    NL
+"### Hook scripts run in an empty environment by default."                   NL
+"### As shown below each section defines environment variables for a"        NL
+"### particular hook script. The [default] section defines environment"      NL
+"### variables for all hook scripts, unless overridden by a hook-specific"   NL
+"### section."                                                               NL
+""                                                                           NL
+"### This example configures a UTF-8 locale for all hook scripts, so that "  NL
+"### special characters, such as umlauts, may be printed to stderr."         NL
+"### If UTF-8 is used with a mod_dav_svn server, the SVNUseUTF8 option must" NL
+"### also be set to 'yes' in httpd.conf."                                    NL
+"### With svnserve, the LANG environment variable of the svnserve process"   NL
+"### must be set to the same value as given here."                           NL
+"[default]"                                                                  NL
+"# LANG = en_US.UTF-8"                                                       NL
+""                                                                           NL
+"### This sets the PATH environment variable for the pre-commit hook."       NL
+"# [pre-commit]"                                                             NL
+"# PATH = /usr/local/bin:/usr/bin:/usr/sbin"                                 NL;
+
+    SVN_ERR_W(svn_io_file_create(svn_dirent_join(repos->conf_path,
+                                                 SVN_REPOS__CONF_HOOKS_ENV,
+                                                 pool),
+                                 hooks_env_contents, pool),
+              _("Creating hooks-env file"));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+/* Baton for parse_hooks_env_option. */
+struct parse_hooks_env_option_baton {
+  /* The name of the section being parsed. If not the default section,
+   * the section name should match the name of a hook to which the
+   * options apply. */
+  const char *section;
+  apr_hash_t *hooks_env;
+} parse_hooks_env_option_baton;
+
+/* An implementation of svn_config_enumerator2_t.
+ * Set environment variable NAME to value VALUE in the environment for
+ * all hooks (in case the current section is the default section),
+ * or the hook with the name corresponding to the current section's name. */
+static svn_boolean_t
+parse_hooks_env_option(const char *name, const char *value,
+                       void *baton, apr_pool_t *pool)
+{
+  struct parse_hooks_env_option_baton *bo = baton;
+  apr_pool_t *result_pool = apr_hash_pool_get(bo->hooks_env);
+  apr_hash_t *hook_env;
+  
+  hook_env = apr_hash_get(bo->hooks_env, bo->section, APR_HASH_KEY_STRING);
+  if (hook_env == NULL)
+    {
+      hook_env = apr_hash_make(result_pool);
+      apr_hash_set(bo->hooks_env, apr_pstrdup(result_pool, bo->section),
+                   APR_HASH_KEY_STRING, hook_env);
+    }
+  apr_hash_set(hook_env, apr_pstrdup(result_pool, name),
+               APR_HASH_KEY_STRING, apr_pstrdup(result_pool, value));
+
+  return TRUE;
+}
+
+struct parse_hooks_env_section_baton {
+  svn_config_t *cfg;
+  apr_hash_t *hooks_env;
+} parse_hooks_env_section_baton;
+
+/* An implementation of svn_config_section_enumerator2_t. */
+static svn_boolean_t
+parse_hooks_env_section(const char *name, void *baton, apr_pool_t *pool)
+{
+  struct parse_hooks_env_section_baton *b = baton;
+  struct parse_hooks_env_option_baton bo;
+
+  bo.section = name;
+  bo.hooks_env = b->hooks_env;
+
+  (void)svn_config_enumerate2(b->cfg, name, parse_hooks_env_option, &bo, pool);
+
+  return TRUE;
+}
+
+/* Parse the hooks env file for this repository. */
+static svn_error_t *
+parse_hooks_env(svn_repos_t *repos,
+                const char *local_abspath,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  svn_config_t *cfg;
+  int n;
+  struct parse_hooks_env_section_baton b;
+
+  SVN_ERR(svn_config_read2(&cfg, local_abspath, FALSE, TRUE, scratch_pool));
+  b.cfg = cfg;
+  b.hooks_env = apr_hash_make(result_pool);
+  n = svn_config_enumerate_sections2(cfg, parse_hooks_env_section, &b,
+                                     scratch_pool);
+  if (n > 0)
+    repos->hooks_env = b.hooks_env;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos_hooks_setenv(svn_repos_t *repos,
+                       const char *hooks_env_path,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  if (hooks_env_path == NULL)
+    hooks_env_path = svn_dirent_join(repos->conf_path,
+                                     SVN_REPOS__CONF_HOOKS_ENV, scratch_pool);
+  else if (!svn_dirent_is_absolute(hooks_env_path))
+    hooks_env_path = svn_dirent_join(repos->conf_path, hooks_env_path,
+                                     scratch_pool);
+
+  SVN_ERR(parse_hooks_env(repos, hooks_env_path, result_pool, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -1145,6 +1265,7 @@ create_svn_repos_t(const char *path, apr
   repos->hook_path = svn_dirent_join(path, SVN_REPOS__HOOK_DIR, pool);
   repos->lock_path = svn_dirent_join(path, SVN_REPOS__LOCK_DIR, pool);
   repos->repository_capabilities = apr_hash_make(pool);
+  repos->hooks_env = NULL;
 
   return repos;
 }
@@ -1685,6 +1806,47 @@ svn_repos_recover4(const char *path,
   return SVN_NO_ERROR;
 }
 
+/* For BDB we fall back on BDB's repos layer lock which means that the
+   repository is unreadable while frozen.
+
+   For FSFS we delegate to the FS layer which uses the FSFS write-lock
+   and an SQLite reserved lock which means the repository is readable
+   while frozen. */
+svn_error_t *
+svn_repos_freeze(const char *path,
+                 svn_error_t *(*freeze_body)(void *, apr_pool_t *),
+                 void *baton,
+                 apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+
+  /* Using a subpool as the only way to unlock the repos lock used by
+     BDB is to clear the pool used to take the lock. */
+  apr_pool_t *subpool = svn_pool_create(pool);
+
+  SVN_ERR(get_repos(&repos, path,
+                    TRUE  /* exclusive */,
+                    FALSE /* non-blocking */,
+                    FALSE /* open-fs */,
+                    NULL, subpool));
+
+  if (strcmp(repos->fs_type, SVN_FS_TYPE_BDB) == 0)
+    {
+      svn_error_t *err = freeze_body(baton, subpool);
+      svn_pool_destroy(subpool);
+      return err;
+    }
+  else
+    {
+      SVN_ERR(svn_fs_open(&repos->fs, repos->db_path, NULL, subpool));
+      SVN_ERR(svn_fs_freeze(svn_repos_fs(repos), freeze_body, baton, subpool));
+    }
+
+  svn_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_repos_db_logfiles(apr_array_header_t **logfiles,
                                    const char *path,
                                    svn_boolean_t only_unused,

Modified: subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.h?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_repos/repos.h Sat Nov 24 20:29:11 2012
@@ -85,6 +85,11 @@ extern "C" {
 /* The extension added to the names of example hook scripts. */
 #define SVN_REPOS__HOOK_DESC_EXT        ".tmpl"
 
+/* The file which contains a custom set of environment variables
+ * passed inherited to hook scripts, in the repository conf directory. */
+#define SVN_REPOS__CONF_HOOKS_ENV "hooks-env"
+/* The name of the default section in the hooks-env config file. */
+#define SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION "default"
 
 /* The configuration file for svnserve, in the repository conf directory. */
 #define SVN_REPOS__CONF_SVNSERVE_CONF "svnserve.conf"
@@ -142,7 +147,15 @@ struct svn_repos_t
   apr_hash_t *repository_capabilities;
 
   /* The environment inherited to hook scripts. If NULL, hooks run
-   * in an empty environment. */
+   * in an empty environment.
+   *
+   * This is a nested hash table.
+   * The entry with name SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION contains the
+   * default environment for all hooks in form of an apr_hash_t with keys
+   * and values describing the names and values of environment variables.
+   * Defaults can be overridden by an entry matching the name of a hook.
+   * E.g. an entry with the name SVN_REPOS__HOOK_PRE_COMMIT provides the
+   * environment specific to the pre-commit hook. */
   apr_hash_t *hooks_env;
 };
 
@@ -153,14 +166,19 @@ struct svn_repos_t
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
    USER is the authenticated name of the user starting the commit.
+
    CAPABILITIES is a list of 'const char *' capability names (using
    SVN_RA_CAPABILITY_*) that the client has self-reported.  Note that
    there is no guarantee the client is telling the truth: the hook
-   should not make security assumptions based on the capabilities. */
+   should not make security assumptions based on the capabilities.
+
+   TXN_NAME is the name of the commit transaction that's just been
+   created. */
 svn_error_t *
 svn_repos__hooks_start_commit(svn_repos_t *repos,
                               const char *user,
                               const apr_array_header_t *capabilities,
+                              const char *txn_name,
                               apr_pool_t *pool);
 
 /* Run the pre-commit hook for REPOS.  Use POOL for any temporary

Modified: subversion/branches/compressed-pristines/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_subr/auth.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_subr/auth.c Sat Nov 24 20:29:11 2012
@@ -523,34 +523,29 @@ svn_auth_get_platform_specific_client_pr
   apr_array_header_t *password_stores;
   int i;
 
+#define SVN__MAYBE_ADD_PROVIDER(list, p) \
+  { if (p) APR_ARRAY_PUSH(list, svn_auth_provider_object_t *) = p; }
+
 #define SVN__DEFAULT_AUTH_PROVIDER_LIST \
          "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi"
 
-  if (config)
-    {
-      svn_config_get
-        (config,
-         &password_stores_config_option,
-         SVN_CONFIG_SECTION_AUTH,
-         SVN_CONFIG_OPTION_PASSWORD_STORES,
-         SVN__DEFAULT_AUTH_PROVIDER_LIST);
-    }
-  else
-    {
-      password_stores_config_option = SVN__DEFAULT_AUTH_PROVIDER_LIST;
-    }
-
   *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
 
-  password_stores
-    = svn_cstring_split(password_stores_config_option, " ,", TRUE, pool);
+  /* Fetch the configured list of password stores, and split them into
+     an array. */
+  svn_config_get(config,
+                 &password_stores_config_option,
+                 SVN_CONFIG_SECTION_AUTH,
+                 SVN_CONFIG_OPTION_PASSWORD_STORES,
+                 SVN__DEFAULT_AUTH_PROVIDER_LIST);
+  password_stores = svn_cstring_split(password_stores_config_option,
+                                      " ,", TRUE, pool);
 
   for (i = 0; i < password_stores->nelts; i++)
     {
       const char *password_store = APR_ARRAY_IDX(password_stores, i,
                                                  const char *);
 
-
       /* GNOME Keyring */
       if (apr_strnatcmp(password_store, "gnome-keyring") == 0)
         {
@@ -558,104 +553,68 @@ svn_auth_get_platform_specific_client_pr
                                                           "gnome_keyring",
                                                           "simple",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
 
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "gnome_keyring",
                                                           "ssl_client_cert_pw",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
-
-          continue;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
         }
-
       /* GPG-AGENT */
-      if (apr_strnatcmp(password_store, "gpg-agent") == 0)
+      else if (apr_strnatcmp(password_store, "gpg-agent") == 0)
         {
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "gpg_agent",
                                                           "simple",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
-
-          continue;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
         }
-
       /* KWallet */
-      if (apr_strnatcmp(password_store, "kwallet") == 0)
+      else if (apr_strnatcmp(password_store, "kwallet") == 0)
         {
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "kwallet",
                                                           "simple",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
 
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "kwallet",
                                                           "ssl_client_cert_pw",
                                                           pool));
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
-
-          continue;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
         }
-
       /* Keychain */
-      if (apr_strnatcmp(password_store, "keychain") == 0)
+      else if (apr_strnatcmp(password_store, "keychain") == 0)
         {
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "keychain",
                                                           "simple",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
 
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "keychain",
                                                           "ssl_client_cert_pw",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
-
-          continue;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
         }
-
       /* Windows */
-      if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
+      else if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
         {
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "windows",
                                                           "simple",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
 
           SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
                                                           "windows",
                                                           "ssl_client_cert_pw",
                                                           pool));
-
-          if (provider)
-            APR_ARRAY_PUSH(*providers, svn_auth_provider_object_t *) = provider;
-
-          continue;
+          SVN__MAYBE_ADD_PROVIDER(*providers, provider);
         }
-
-      return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
-                               _("Invalid config: unknown password store "
-                                 "'%s'"),
-                               password_store);
     }
 
   return SVN_NO_ERROR;