You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC

svn commit: r1442344 [12/39] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/tree.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/tree.c Mon Feb  4 20:48:05 2013
@@ -321,7 +321,7 @@ auto_clear_dag_cache(fs_fs_dag_cache_t* 
 {
   if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT)
     {
-      apr_pool_clear(cache->pool);
+      svn_pool_clear(cache->pool);
 
       memset(cache->buckets, 0, sizeof(cache->buckets));
       cache->insertions = 0;
@@ -499,6 +499,9 @@ dag_node_cache_set(svn_fs_root_t *root,
 
   SVN_ERR_ASSERT(*path == '/');
 
+  /* Do *not* attempt to dup and put the node into L1.
+   * dup() is twice as expensive as an L2 lookup (which will set also L1).
+   */
   locate_cache(&cache, &key, root, path, pool);
 
   return svn_cache__set(cache, key, node, pool);
@@ -849,8 +852,19 @@ typedef enum open_path_flags_t {
      directories must exist, as usual.)  If the last component doesn't
      exist, simply leave the `node' member of the bottom parent_path
      component zero.  */
-  open_path_last_optional = 1
+  open_path_last_optional = 1,
 
+  /* When this flag is set, don't bother to lookup the DAG node in
+     our caches because we already tried this.  Ignoring this flag
+     has no functional impact.  */
+  open_path_uncached = 2,
+
+  /* Assume that the path parameter is already in canonical form. */
+  open_path_is_canonical = 4,
+
+  /* The caller does not care about the parent node chain but only
+     the final DAG node. */
+  open_path_node_only = 8
 } open_path_flags_t;
 
 
@@ -873,6 +887,10 @@ typedef enum open_path_flags_t {
    callers that create new nodes --- we find the parent directory for
    them, and tell them whether the entry exists already.
 
+   The remaining bits in FLAGS are hints that allow this function
+   to take shortcuts based on knowledge that the caller provides,
+   such as the fact that PATH is already in canonical form.
+
    NOTE: Public interfaces which only *read* from the filesystem
    should not call this function directly, but should instead use
    get_dag().
@@ -886,23 +904,47 @@ open_path(parent_path_t **parent_path_p,
           apr_pool_t *pool)
 {
   svn_fs_t *fs = root->fs;
-  dag_node_t *here; /* The directory we're currently looking at.  */
-  parent_path_t *parent_path; /* The path from HERE up to the root.  */
+  dag_node_t *here = NULL; /* The directory we're currently looking at.  */
+  parent_path_t *parent_path; /* The path from HERE up to the root. */
   const char *rest; /* The portion of PATH we haven't traversed yet.  */
-  const char *canon_path = svn_fs__is_canonical_abspath(path)
+
+  /* ensure a canonical path representation */
+  const char *canon_path = (   (flags & open_path_is_canonical)
+                            || svn_fs__is_canonical_abspath(path))
                          ? path
                          : svn_fs__canonicalize_abspath(path, pool);
   const char *path_so_far = "/";
   apr_pool_t *iterpool = svn_pool_create(pool);
 
-  /* Make a parent_path item for the root node, using its own current
-     copy id.  */
-  SVN_ERR(root_node(&here, root, pool));
+  /* callers often traverse the tree in some path-based order.  That means
+     a sibbling of PATH has been resently accessed.  Try to start the lookup
+     directly at the parent node, if the caller did not requested the full
+     parent chain. */
+  const char *directory;
+  if (flags & open_path_node_only)
+    {
+      directory = svn_dirent_dirname(canon_path, pool);
+      if (directory[1] != 0) /* root nodes are covered anyway */
+        SVN_ERR(dag_node_cache_get(&here, root, directory, TRUE, pool));
+    }
+
+  /* did the shortcut work? */
+  if (here)
+    {
+      path_so_far = directory;
+      rest = canon_path + strlen(directory) + 1;
+    }
+  else
+    {
+      /* Make a parent_path item for the root node, using its own current
+         copy id.  */
+      SVN_ERR(root_node(&here, root, pool));
+      rest = canon_path + 1; /* skip the leading '/', it saves in iteration */
+    }
+ 
   parent_path = make_parent_path(here, 0, 0, pool);
   parent_path->copy_inherit = copy_id_inherit_self;
 
-  rest = canon_path + 1; /* skip the leading '/', it saves in iteration */
-
   /* Whenever we are at the top of this loop:
      - HERE is our current directory,
      - ID is the node revision ID of HERE,
@@ -935,13 +977,16 @@ open_path(parent_path_t **parent_path_p,
           copy_id_inherit_t inherit;
           const char *copy_path = NULL;
           svn_error_t *err = SVN_NO_ERROR;
-          dag_node_t *cached_node;
+          dag_node_t *cached_node = NULL;
 
           /* If we found a directory entry, follow it.  First, we
              check our node cache, and, failing that, we hit the DAG
-             layer. */
-          SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far, TRUE,
-                                     pool));
+             layer.  Don't bother to contact the cache for the last
+             element if we already know the lookup to fail for the
+             complete path. */
+          if (next || !(flags & open_path_uncached))
+            SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far,
+                                       TRUE, pool));
           if (cached_node)
             child = cached_node;
           else
@@ -974,14 +1019,22 @@ open_path(parent_path_t **parent_path_p,
           /* Other errors we return normally.  */
           SVN_ERR(err);
 
-          /* Now, make a parent_path item for CHILD. */
-          parent_path = make_parent_path(child, entry, parent_path, pool);
-          if (txn_id)
+          if (flags & open_path_node_only)
+            {
+              /* Shortcut: the caller only wan'ts the final DAG node. */
+              parent_path->node = child;
+            }
+          else
             {
-              SVN_ERR(get_copy_inheritance(&inherit, &copy_path,
-                                           fs, parent_path, txn_id, iterpool));
-              parent_path->copy_inherit = inherit;
-              parent_path->copy_src_path = apr_pstrdup(pool, copy_path);
+              /* Now, make a parent_path item for CHILD. */
+              parent_path = make_parent_path(child, entry, parent_path, pool);
+              if (txn_id)
+                {
+                  SVN_ERR(get_copy_inheritance(&inherit, &copy_path, fs,
+                                               parent_path, txn_id, iterpool));
+                  parent_path->copy_inherit = inherit;
+                  parent_path->copy_src_path = apr_pstrdup(pool, copy_path);
+                }
             }
 
           /* Cache the node we found (if it wasn't already cached). */
@@ -1144,7 +1197,9 @@ get_dag(dag_node_t **dag_node_p,
         {
           /* Call open_path with no flags, as we want this to return an
            * error if the node for which we are searching doesn't exist. */
-          SVN_ERR(open_path(&parent_path, root, path, 0, NULL, pool));
+          SVN_ERR(open_path(&parent_path, root, path,
+                            open_path_uncached | open_path_is_canonical
+                            | open_path_node_only, NULL, pool));
           node = parent_path->node;
 
           /* No need to cache our find -- open_path() will do that for us. */
@@ -3164,7 +3219,7 @@ static svn_error_t *fs_closest_copy(svn_
   if (kind == svn_node_none)
     return SVN_NO_ERROR;
   SVN_ERR(open_path(&copy_dst_parent_path, copy_dst_root, path,
-                    0, NULL, pool));
+                    open_path_node_only, NULL, pool));
   copy_dst_node = copy_dst_parent_path->node;
   if (! svn_fs_fs__id_check_related(svn_fs_fs__dag_get_id(copy_dst_node),
                                     svn_fs_fs__dag_get_id(parent_path->node)))
@@ -3245,7 +3300,7 @@ prev_location(const char **prev_path,
   */
   SVN_ERR(fs_copied_from(&copy_src_rev, &copy_src_path,
                          copy_root, copy_path, pool));
-  remainder_path = svn_relpath_skip_ancestor(copy_path, path);
+  remainder_path = svn_fspath__skip_ancestor(copy_path, path);
   *prev_path = svn_fspath__join(copy_src_path, remainder_path, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;
@@ -3777,7 +3832,8 @@ get_mergeinfo_for_path_internal(svn_merg
 
   path = svn_fs__canonicalize_abspath(path, scratch_pool);
 
-  SVN_ERR(open_path(&parent_path, rev_root, path, 0, NULL, scratch_pool));
+  SVN_ERR(open_path(&parent_path, rev_root, path, open_path_is_canonical,
+                    NULL, scratch_pool));
 
   if (inherit == svn_mergeinfo_nearest_ancestor && ! parent_path->parent)
     return SVN_NO_ERROR;
@@ -4285,8 +4341,6 @@ svn_fs_fs__verify_root(svn_fs_root_t *ro
   /* Verify explicitly the predecessor of the root. */
   {
     const svn_fs_id_t *pred_id;
-    dag_node_t *pred;
-    svn_revnum_t pred_rev;
 
     /* Only r0 should have no predecessor. */
     SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, frd->root_dir));
@@ -4302,8 +4356,7 @@ svn_fs_fs__verify_root(svn_fs_root_t *ro
     /* Check the predecessor's revision. */
     if (pred_id)
       {
-        SVN_ERR(svn_fs_fs__dag_get_node(&pred, root->fs, pred_id, pool));
-        SVN_ERR(svn_fs_fs__dag_get_revision(&pred_rev, pred, pool));
+        svn_revnum_t pred_rev = svn_fs_fs__id_rev(pred_id);
         if (pred_rev+1 != root->rev)
           /* Issue #4129. */
           return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra/compat.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra/compat.c Mon Feb  4 20:48:05 2013
@@ -630,7 +630,6 @@ fr_log_message_receiver(void *baton,
 {
   struct fr_log_message_baton *lmb = baton;
   struct rev *rev;
-  apr_hash_index_t *hi;
 
   rev = apr_palloc(lmb->pool, sizeof(*rev));
   rev->revision = log_entry->revision;
@@ -639,17 +638,7 @@ fr_log_message_receiver(void *baton,
   lmb->eldest = rev;
 
   /* Duplicate log_entry revprops into rev->props */
-  rev->props = apr_hash_make(lmb->pool);
-  for (hi = apr_hash_first(pool, log_entry->revprops); hi;
-       hi = apr_hash_next(hi))
-    {
-      void *val;
-      const void *key;
-
-      apr_hash_this(hi, &key, NULL, &val);
-      apr_hash_set(rev->props, apr_pstrdup(lmb->pool, key), APR_HASH_KEY_STRING,
-                   svn_string_dup(val, lmb->pool));
-    }
+  rev->props = svn_prop_hash_dup(log_entry->revprops, lmb->pool);
 
   return prev_log_path(&lmb->path, &lmb->action,
                        &lmb->copyrev, log_entry->changed_paths2,
@@ -946,7 +935,9 @@ svn_ra__get_inherited_props_walk(svn_ra_
         {
           svn_prop_inherited_item_t *new_iprop =
             apr_palloc(result_pool, sizeof(*new_iprop));
-          new_iprop->path_or_url = apr_pstrdup(result_pool, parent_url);
+          new_iprop->path_or_url = svn_uri_skip_ancestor(repos_root_url,
+                                                         parent_url,
+                                                         result_pool);
           new_iprop->prop_hash = final_hash;
           svn_sort__array_insert(&new_iprop, *inherited_props, 0);
         }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra/deprecated.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra/deprecated.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra/deprecated.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra/deprecated.h Mon Feb  4 20:48:05 2013
@@ -28,7 +28,8 @@
 
 #include <apr_hash.h>
 
-#include "svn_editor.h"
+#include "private/svn_editor.h"
+
 
 #ifdef __cplusplus
 extern "C" {

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra/editor.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra/editor.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra/editor.c Mon Feb  4 20:48:05 2013
@@ -27,11 +27,11 @@
 #include "svn_pools.h"
 #include "svn_ra.h"
 #include "svn_delta.h"
-#include "svn_editor.h"
 #include "svn_dirent_uri.h"
 
 #include "private/svn_ra_private.h"
 #include "private/svn_delta_private.h"
+#include "private/svn_editor.h"
 
 #include "ra_loader.h"
 #include "svn_private_config.h"

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.c Mon Feb  4 20:48:05 2013
@@ -140,8 +140,8 @@ load_ra_module(svn_ra__init_func_t *func
     const char *compat_funcname;
     apr_status_t status;
 
-    libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.0",
-                           ra_name, SVN_VER_MAJOR);
+    libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.%d",
+                           ra_name, SVN_VER_MAJOR, SVN_SOVERSION);
     funcname = apr_psprintf(pool, "svn_ra_%s__init", ra_name);
     compat_funcname = apr_psprintf(pool, "svn_ra_%s_init", ra_name);
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra/ra_loader.h Mon Feb  4 20:48:05 2013
@@ -496,11 +496,11 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
 
 
 /**
- * Fallback logic for svn_ra_get_fileX and svn_ra_get_dirX when those APIs
+ * Fallback logic for svn_ra_get_inherited_props() when that API
  * need to find PATH's inherited properties on a legacy server that
  * doesn't have the SVN_RA_CAPABILITY_INHERITED_PROPS capability.
  *
- * All arguments are as per the two aforementioned APIs.
+ * All arguments are as per svn_ra_get_inherited_props().
  */
 svn_error_t *
 svn_ra__get_inherited_props_walk(svn_ra_session_t *session,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_local/ra_plugin.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_local/ra_plugin.c Mon Feb  4 20:48:05 2013
@@ -1058,22 +1058,12 @@ get_node_props(apr_hash_t **props,
       SVN_ERR(svn_fs_node_proplist(props, root, path, result_pool));
     }
 
-  /* Turn FS-path keys into URLs. */
+  /* Get inherited properties if requested. */
   if (inherited_props)
     {
-      int i;
-
       SVN_ERR(svn_repos_fs_get_inherited_props(inherited_props, root, path,
-                                               NULL, NULL,
+                                               NULL, NULL, NULL,
                                                result_pool, scratch_pool));
-
-      for (i = 0; i < (*inherited_props)->nelts; i++)
-        {
-          svn_prop_inherited_item_t *i_props =
-            APR_ARRAY_IDX(*inherited_props, i, svn_prop_inherited_item_t *);
-          i_props->path_or_url = svn_path_url_add_component2(
-            sess->repos_url, i_props->path_or_url, result_pool);
-        }
     }
 
   /* Now add some non-tweakable metadata to the hash as well... */
@@ -1230,7 +1220,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
           apr_hash_t *prophash;
           const char *datestring, *entryname, *fullpath;
           svn_fs_dirent_t *fs_entry;
-          svn_dirent_t *entry = apr_pcalloc(pool, sizeof(*entry));
+          svn_dirent_t *entry = svn_dirent_create(pool);
 
           svn_pool_clear(subpool);
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/commit.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/commit.c Mon Feb  4 20:48:05 2013
@@ -1294,9 +1294,9 @@ open_root(void *edit_baton,
     {
       post_response_ctx_t *prc;
       const char *rel_path;
-      svn_boolean_t post_with_revprops =
-        apr_hash_get(ctx->session->supported_posts, "create-txn-with-props",
-                     APR_HASH_KEY_STRING) ? TRUE : FALSE;
+      svn_boolean_t post_with_revprops
+        = (apr_hash_get(ctx->session->supported_posts, "create-txn-with-props",
+                        APR_HASH_KEY_STRING) != NULL);
 
       /* Create our activity URL now on the server. */
       handler = apr_pcalloc(ctx->pool, sizeof(*handler));
@@ -1466,16 +1466,10 @@ open_root(void *edit_baton,
       for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
            hi = apr_hash_next(hi))
         {
-          const void *key;
-          void *val;
-          const char *name;
-          svn_string_t *value;
+          const char *name = svn__apr_hash_index_key(hi);
+          svn_string_t *value = svn__apr_hash_index_val(hi);
           const char *ns;
 
-          apr_hash_this(hi, &key, NULL, &val);
-          name = key;
-          value = val;
-
           if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
             {
               ns = SVN_DAV_PROP_NS_SVN;
@@ -2267,7 +2261,6 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_delta_editor_t *editor;
   commit_context_t *ctx;
-  apr_hash_index_t *hi;
   const char *repos_root;
   const char *base_relpath;
   svn_boolean_t supports_ephemeral_props;
@@ -2279,17 +2272,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   ctx->session = session;
   ctx->conn = session->conns[0];
 
-  ctx->revprop_table = apr_hash_make(pool);
-  for (hi = apr_hash_first(pool, revprop_table); hi; hi = apr_hash_next(hi))
-    {
-      const void *key;
-      apr_ssize_t klen;
-      void *val;
-
-      apr_hash_this(hi, &key, &klen, &val);
-      apr_hash_set(ctx->revprop_table, apr_pstrdup(pool, key), klen,
-                   svn_string_dup(val, pool));
-    }
+  ctx->revprop_table = svn_prop_hash_dup(revprop_table, pool);
 
   /* If the server supports ephemeral properties, add some carrying
      interesting version information. */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/locks.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/locks.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/locks.c Mon Feb  4 20:48:05 2013
@@ -261,7 +261,7 @@ handle_lock(serf_request_t *request,
                                request, response, ctx->handler, pool));
     }
 
-  if (ctx->read_headers == FALSE)
+  if (!ctx->read_headers)
     {
       serf_bucket_t *headers;
       const char *val;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/options.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/options.c Mon Feb  4 20:48:05 2013
@@ -211,6 +211,14 @@ capabilities_headers_iterator_callback(v
                        SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, APR_HASH_KEY_STRING,
                        capability_yes);
         }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INLINE_PROPS, vals))
+        {
+          session->supports_inline_props = TRUE;
+        }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_REPLAY_REV_RESOURCE, vals))
+        {
+          session->supports_rev_rsrc_replay = TRUE;
+        }
     }
 
   /* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -280,6 +288,10 @@ capabilities_headers_iterator_callback(v
         {
           opt_ctx->youngest_rev = SVN_STR_TO_REV(val);
         }
+      else if (svn_cstring_casecmp(key, SVN_DAV_ALLOW_BULK_UPDATES) == 0)
+        {
+          session->server_allows_bulk = apr_pstrdup(session->pool, val);
+        }
       else if (svn_cstring_casecmp(key, SVN_DAV_SUPPORTED_POSTS_HEADER) == 0)
         {
           /* May contain multiple values, separated by commas. */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/property.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/property.c Mon Feb  4 20:48:05 2013
@@ -526,7 +526,7 @@ create_propfind_body(serf_bucket_t **bkt
     }
 
   /* If we're not doing an allprop, add <prop> tags. */
-  if (requested_allprop == FALSE)
+  if (!requested_allprop)
     {
       tmp = SERF_BUCKET_SIMPLE_STRING_LEN("<prop>",
                                           sizeof("<prop>")-1,
@@ -540,7 +540,7 @@ create_propfind_body(serf_bucket_t **bkt
 
   serf_bucket_aggregate_prepend(body_bkt, tmp);
 
-  if (requested_allprop == FALSE)
+  if (!requested_allprop)
     {
       tmp = SERF_BUCKET_SIMPLE_STRING_LEN("</prop>",
                                           sizeof("</prop>")-1,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/ra_serf.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/ra_serf.h Mon Feb  4 20:48:05 2013
@@ -94,10 +94,12 @@ typedef struct svn_ra_serf__connection_t
 
 } svn_ra_serf__connection_t;
 
-/** Max. number of connctions we'll open to the server. 
- *  Note: minimum 2 connections are required for ra_serf to function correctly!
+/** Maximum value we'll allow for the http-max-connections config option.
+ *
+ * Note: minimum 2 connections are required for ra_serf to function
+ * correctly!
  */
-#define MAX_NR_OF_CONNS 4
+#define SVN_RA_SERF__MAX_CONNECTIONS_LIMIT 8
 
 /*
  * The master serf RA session.
@@ -111,6 +113,10 @@ struct svn_ra_serf__session_t {
   /* The current context */
   serf_context_t *context;
 
+  /* The maximum number of connections we'll use for parallelized
+     fetch operations (updates, etc.) */
+  apr_int64_t max_connections;
+
   /* Are we using ssl */
   svn_boolean_t using_ssl;
 
@@ -121,7 +127,7 @@ struct svn_ra_serf__session_t {
   const char *useragent;
 
   /* The current connection */
-  svn_ra_serf__connection_t *conns[MAX_NR_OF_CONNS];
+  svn_ra_serf__connection_t *conns[SVN_RA_SERF__MAX_CONNECTIONS_LIMIT];
   int num_conns;
   int cur_conn;
 
@@ -223,6 +229,26 @@ struct svn_ra_serf__session_t {
   /*** End HTTP v2 stuff ***/
 
   svn_ra_serf__blncache_t *blncache;
+
+  /* Trisate flag that indicates user preference for using bulk updates
+     (svn_tristate_true) with all the properties and content in the
+     update-report response. If svn_tristate_false, request a skelta
+     update-report with inlined properties. If svn_tristate_unknown then use
+     server preference. */
+  svn_tristate_t bulk_updates;
+
+  /* Indicates if the server wants bulk update requests (Prefer) or only
+     accepts skelta requests (Off). If this value is On both options are 
+     allowed. */
+  const char *server_allows_bulk;
+
+  /* Indicates if the server supports sending inlined props in update editor
+   * in skelta mode (send-all == 'false'). */
+  svn_boolean_t supports_inline_props;
+
+  /* Indicates whether the server supports issuing replay REPORTs
+     against rev resources (children of `rev_stub', elsestruct). */
+  svn_boolean_t supports_rev_rsrc_replay;
 };
 
 #define SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(sess) ((sess)->me_resource != NULL)

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/replay.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/replay.c Mon Feb  4 20:48:05 2013
@@ -107,16 +107,17 @@ typedef struct replay_context_t {
   const svn_delta_editor_t *editor;
   void *editor_baton;
 
-  /* current revision */
+  /* Path and revision used to filter replayed changes.  If
+     INCLUDE_PATH is non-NULL, REVISION is unnecessary and will not be
+     included in the replay REPORT.  (Because the REPORT is being
+     aimed an HTTP v2 revision resource.)  */
+  const char *include_path;
   svn_revnum_t revision;
 
   /* Information needed to create the replay report body */
   svn_revnum_t low_water_mark;
   svn_boolean_t send_deltas;
 
-  /* Cached report target url */
-  const char *report_target;
-
   /* Target and revision to fetch revision properties on */
   const char *revprop_target;
   svn_revnum_t revprop_rev;
@@ -128,8 +129,9 @@ typedef struct replay_context_t {
   /* Keep a reference to the XML parser ctx to report any errors. */
   svn_ra_serf__xml_parser_t *parser_ctx;
 
-  /* The propfind for the revision properties of the current revision */
+  /* Handlers for the PROPFIND and REPORT for the current revision. */
   svn_ra_serf__handler_t *propfind_handler;
+  svn_ra_serf__handler_t *report_handler;
 
 } replay_context_t;
 
@@ -602,10 +604,22 @@ create_replay_body(serf_bucket_t **bkt,
                                     "xmlns:S", SVN_XML_NAMESPACE,
                                     NULL);
 
-  svn_ra_serf__add_tag_buckets(body_bkt,
-                               "S:revision",
-                               apr_ltoa(ctx->src_rev_pool, ctx->revision),
-                               alloc);
+  /* If we have a non-NULL include path, we add it to the body and
+     omit the revision; otherwise, the reverse. */
+  if (ctx->include_path)
+    {
+      svn_ra_serf__add_tag_buckets(body_bkt,
+                                   "S:include-path",
+                                   ctx->include_path,
+                                   alloc);
+    }
+  else
+    {
+      svn_ra_serf__add_tag_buckets(body_bkt,
+                                   "S:revision",
+                                   apr_ltoa(ctx->src_rev_pool, ctx->revision),
+                                   alloc);
+    }
   svn_ra_serf__add_tag_buckets(body_bkt,
                                "S:low-water-mark",
                                apr_ltoa(ctx->src_rev_pool, ctx->low_water_mark),
@@ -648,14 +662,13 @@ svn_ra_serf__replay(svn_ra_session_t *ra
   replay_ctx->revision = revision;
   replay_ctx->low_water_mark = low_water_mark;
   replay_ctx->send_deltas = send_deltas;
-  replay_ctx->report_target = report_target;
   replay_ctx->revs_props = apr_hash_make(replay_ctx->src_rev_pool);
 
   handler = apr_pcalloc(pool, sizeof(*handler));
 
   handler->handler_pool = pool;
   handler->method = "REPORT";
-  handler->path = session->session_url_str;
+  handler->path = session->session_url.path;
   handler->body_delegate = create_replay_body;
   handler->body_delegate_baton = replay_ctx;
   handler->body_type = "text/xml";
@@ -676,12 +689,17 @@ svn_ra_serf__replay(svn_ra_session_t *ra
 
   /* This is only needed to handle errors during XML parsing. */
   replay_ctx->parser_ctx = parser_ctx;
+  replay_ctx->report_handler = handler; /* unused */
 
   svn_ra_serf__request_create(handler);
 
   err = svn_ra_serf__context_run_wait(&replay_ctx->done, session, pool);
 
-  SVN_ERR(err);
+  SVN_ERR(svn_error_compose_create(
+              svn_ra_serf__error_on_status(handler->sline.code,
+                                           handler->path,
+                                           handler->location),
+              err));
 
   return SVN_NO_ERROR;
 }
@@ -698,8 +716,8 @@ svn_ra_serf__replay(svn_ra_session_t *ra
  * optimally. Originally we used 5 as the max. number of outstanding
  * requests, but this turned out to be too low.
  *
- * Serf doesn't exit out of the serf_context_run loop as long as it
- * has data to send or receive. With small responses (revs of a few
+ * Serf doesn't exit out of the svn_ra_serf__context_run_wait loop as long as
+ * it has data to send or receive. With small responses (revs of a few
  * kB), serf doesn't come out of this loop at all. So with
  * MAX_OUTSTANDING_REQUESTS set to a low number, there's a big chance
  * that serf handles those requests completely in its internal loop,
@@ -732,14 +750,41 @@ svn_ra_serf__replay_range(svn_ra_session
   svn_revnum_t rev = start_revision;
   const char *report_target;
   int active_reports = 0;
-  apr_interval_time_t waittime_left = session->timeout;
+  const char *include_path;
 
   SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
 
+  /* Prior to 1.8, mod_dav_svn expect to get replay REPORT requests
+     aimed at the session URL.  But that's incorrect -- these reports
+     aren't about specific resources -- they are above revisions.  The
+     path-based filtering offered by this API is just that: a filter
+     applied to the full set of changes made in the revision.  As
+     such, the correct target for these REPORT requests is the "me
+     resource" (or, pre-http-v2, the default VCC).
+
+     Our server should have told us if it supported this protocol
+     correction.  If so, we aimed our report at the correct resource
+     and include the filtering path as metadata within the report
+     body.  Otherwise, we fall back to the pre-1.8 behavior and just
+     wish for the best.
+
+     See issue #4287:
+     http://subversion.tigris.org/issues/show_bug.cgi?id=4287
+  */
+  if (session->supports_rev_rsrc_replay)
+    {
+      SVN_ERR(svn_ra_serf__get_relative_path(&include_path,
+                                             session->session_url.path,
+                                             session, session->conns[0],
+                                             pool));
+    }
+  else
+    {
+      include_path = NULL;
+    }
+
   while (active_reports || rev <= end_revision)
     {
-      apr_status_t status;
-      svn_error_t *err;
       svn_ra_serf__list_t *done_list;
       svn_ra_serf__list_t *done_reports = NULL;
       replay_context_t *replay_ctx;
@@ -754,6 +799,7 @@ svn_ra_serf__replay_range(svn_ra_session
           svn_ra_serf__handler_t *handler;
           svn_ra_serf__xml_parser_t *parser_ctx;
           apr_pool_t *ctx_pool = svn_pool_create(pool);
+          const char *replay_target;
 
           replay_ctx = apr_pcalloc(ctx_pool, sizeof(*replay_ctx));
           replay_ctx->src_rev_pool = ctx_pool;
@@ -761,19 +807,20 @@ svn_ra_serf__replay_range(svn_ra_session
           replay_ctx->revfinish_func = revfinish_func;
           replay_ctx->replay_baton = replay_baton;
           replay_ctx->done = FALSE;
+          replay_ctx->include_path = include_path;
           replay_ctx->revision = rev;
           replay_ctx->low_water_mark = low_water_mark;
           replay_ctx->send_deltas = send_deltas;
           replay_ctx->done_item.data = replay_ctx;
+
           /* Request all properties of a certain revision. */
-          replay_ctx->report_target = report_target;
           replay_ctx->revs_props = apr_hash_make(replay_ctx->src_rev_pool);
 
           if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
-           {
-             replay_ctx->revprop_target = apr_psprintf(pool, "%s/%ld",
-                                                       session->rev_stub, rev);
-             replay_ctx->revprop_rev = SVN_INVALID_REVNUM;
+            {
+              replay_ctx->revprop_target = apr_psprintf(pool, "%s/%ld",
+                                                        session->rev_stub, rev);
+              replay_ctx->revprop_rev = SVN_INVALID_REVNUM;
             }
           else
             {
@@ -793,12 +840,22 @@ svn_ra_serf__replay_range(svn_ra_session
           /* Spin up the serf request for the PROPFIND.  */
           svn_ra_serf__request_create(replay_ctx->propfind_handler);
 
-          /* Send the replay report request. */
+          /* Send the replay REPORT request. */
+          if (session->supports_rev_rsrc_replay)
+            {
+              replay_target = apr_psprintf(pool, "%s/%ld",
+                                           session->rev_stub, rev);
+            }
+          else
+            {
+              replay_target = session->session_url.path;
+            }
+
           handler = apr_pcalloc(replay_ctx->src_rev_pool, sizeof(*handler));
 
           handler->handler_pool = replay_ctx->src_rev_pool;
           handler->method = "REPORT";
-          handler->path = session->session_url_str;
+          handler->path = replay_target;
           handler->body_delegate = create_replay_body;
           handler->body_delegate_baton = replay_ctx;
           handler->conn = session->conns[0];
@@ -824,6 +881,7 @@ svn_ra_serf__replay_range(svn_ra_session
           parser_ctx->done_item = &replay_ctx->done_item;
           handler->response_handler = svn_ra_serf__handle_xml_parser;
           handler->response_baton = parser_ctx;
+          replay_ctx->report_handler = handler;
 
           /* This is only needed to handle errors during XML parsing. */
           replay_ctx->parser_ctx = parser_ctx;
@@ -834,62 +892,8 @@ svn_ra_serf__replay_range(svn_ra_session
           active_reports++;
         }
 
-      /* Run the serf loop, send outgoing and process incoming requests.
-         This request will block when there are no more requests to send or
-         responses to receive, so we have to be careful on our bookkeeping.
-
-         ### we should probably adjust this timeout. if we get (say) 3
-         ### requests completed, then we want to exit immediately rather
-         ### than block for a few seconds. that will allow us to clear up
-         ### those 3 requests. if we have queued all of our revisions,
-         ### then we may want to block until timeout since we really don't
-         ### have much work other than destroying memory. (though that
-         ### is important, as we could end up with 50 src_rev_pool pools)
-
-         ### idea: when a revision is marked DONE, we can probably destroy
-         ### most of the memory. that will reduce pressue to have serf
-         ### return control to us, to complete the major memory disposal.
-
-         ### theoretically, we should use an iterpool here, but it turns
-         ### out that serf doesn't even use the pool param. if we grow
-         ### an iterpool in this loop for other purposes, then yeah: go
-         ### ahead and apply it here, too, in case serf eventually uses
-         ### that parameter.
-      */
-      status = serf_context_run(session->context,
-                                SVN_RA_SERF__CONTEXT_RUN_DURATION,
-                                pool);
-
-      err = session->pending_error;
-      session->pending_error = NULL;
-
-      /* If the context duration timeout is up, we'll subtract that
-         duration from the total time alloted for such things.  If
-         there's no time left, we fail with a message indicating that
-         the connection timed out.  */
-      if (APR_STATUS_IS_TIMEUP(status))
-        {
-          svn_error_clear(err);
-          err = SVN_NO_ERROR;
-          status = 0;
-
-          if (session->timeout)
-            {
-              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-                {
-                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-                }
-              else
-                {
-                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                          _("Connection timed out"));
-                }
-            }
-        }
-      else
-        {
-          waittime_left = session->timeout;
-        }
+      /* Run the serf loop. */
+      SVN_ERR(svn_ra_serf__context_run_wait(&replay_ctx->done, session, pool));
 
       /* Substract the number of completely handled responses from our
          total nr. of open requests', so we'll know when to stop this loop.
@@ -898,18 +902,16 @@ svn_ra_serf__replay_range(svn_ra_session
       while (done_list)
         {
           replay_context_t *ctx = (replay_context_t *)done_list->data;
+          svn_ra_serf__handler_t *done_handler = ctx->report_handler;
 
           done_list = done_list->next;
+          SVN_ERR(svn_ra_serf__error_on_status(done_handler->sline.code,
+                                               done_handler->path,
+                                               done_handler->location));
           svn_pool_destroy(ctx->src_rev_pool);
           active_reports--;
         }
 
-      SVN_ERR(err);
-      if (status)
-        {
-          return svn_ra_serf__wrap_err(status,
-                                       _("Error retrieving replay REPORT"));
-        }
       done_reports = NULL;
     }
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c Mon Feb  4 20:48:05 2013
@@ -148,7 +148,6 @@ load_config(svn_ra_serf__session_t *sess
   const char *timeout_str = NULL;
   const char *exceptions;
   apr_port_t proxy_port;
-  svn_boolean_t is_exception = FALSE;
 
   if (config_hash)
     {
@@ -188,16 +187,11 @@ load_config(svn_ra_serf__session_t *sess
   /* Use the default proxy-specific settings if and only if
      "http-proxy-exceptions" is not set to exclude this host. */
   svn_config_get(config, &exceptions, SVN_CONFIG_SECTION_GLOBAL,
-                 SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, NULL);
-  if (exceptions)
+                 SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, "");
+  if (! svn_cstring_match_glob_list(session->session_url.hostname,
+                                    svn_cstring_split(exceptions, ",",
+                                                      TRUE, pool)))
     {
-      apr_array_header_t *l = svn_cstring_split(exceptions, ",", TRUE, pool);
-      is_exception = svn_cstring_match_glob_list(session->session_url.hostname,
-                                                 l);
-    }
-  if (! is_exception)
-    {
-      /* Load the global proxy server settings, if set. */
       svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
                      SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
       svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
@@ -218,6 +212,20 @@ load_config(svn_ra_serf__session_t *sess
   svn_config_get(config, &session->ssl_authorities, SVN_CONFIG_SECTION_GLOBAL,
                  SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
 
+  /* If set, read the flag that tells us to do bulk updates or not. Defaults
+     to skelta updates. */
+  SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates,
+                                  SVN_CONFIG_SECTION_GLOBAL,
+                                  SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                                  "auto",
+                                  svn_tristate_unknown));
+
+  /* Load the maximum number of parallel session connections. */
+  svn_config_get_int64(config, &session->max_connections,
+                       SVN_CONFIG_SECTION_GLOBAL,
+                       SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+                       SVN_CONFIG_DEFAULT_OPTION_HTTP_MAX_CONNECTIONS);
+
   if (config)
     server_group = svn_config_find_group(config,
                                          session->session_url.hostname,
@@ -237,24 +245,51 @@ load_config(svn_ra_serf__session_t *sess
       svn_auth_set_parameter(session->wc_callbacks->auth_baton,
                              SVN_AUTH_PARAM_SERVER_GROUP, server_group);
 
-      /* Load the group proxy server settings, overriding global settings. */
+      /* Load the group proxy server settings, overriding global
+         settings.  We intentionally ignore 'http-proxy-exceptions'
+         here because, well, if this site was an exception, why is
+         there a per-server proxy configuration for it?  */
       svn_config_get(config, &proxy_host, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, proxy_host);
       svn_config_get(config, &port_str, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, port_str);
       svn_config_get(config, &session->proxy_username, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME,
+                     session->proxy_username);
       svn_config_get(config, &session->proxy_password, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD,
+                     session->proxy_password);
 
       /* Load the group ssl settings. */
       SVN_ERR(svn_config_get_bool(config, &session->trust_default_ca,
                                   server_group,
                                   SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA,
-                                  TRUE));
+                                  session->trust_default_ca));
       svn_config_get(config, &session->ssl_authorities, server_group,
-                     SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
-    }
+                     SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES,
+                     session->ssl_authorities);
+
+      /* Load the group bulk updates flag. */
+      SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates,
+                                      server_group,
+                                      SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                                      "auto",
+                                      session->bulk_updates));
+
+      /* Load the maximum number of parallel session connections,
+         overriding global values. */
+      svn_config_get_int64(config, &session->max_connections,
+                           server_group, SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+                           session->max_connections);
+    }
+
+  /* Don't allow the http-max-connections value to be larger than our
+     compiled-in limit, or to be too small to operate.  Broken
+     functionality and angry administrators are equally undesirable. */
+  if (session->max_connections > SVN_RA_SERF__MAX_CONNECTIONS_LIMIT)
+    session->max_connections = SVN_RA_SERF__MAX_CONNECTIONS_LIMIT;
+  if (session->max_connections < 2)
+    session->max_connections = 2;
 
   /* Parse the connection timeout value, if any. */
   session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT);
@@ -294,7 +329,9 @@ load_config(svn_ra_serf__session_t *sess
       proxy_port = (apr_port_t) port;
     }
   else
-    proxy_port = 80;
+    {
+      proxy_port = 80;
+    }
 
   if (proxy_host)
     {
@@ -314,7 +351,9 @@ load_config(svn_ra_serf__session_t *sess
       serf_config_proxy(session->context, proxy_addr);
     }
   else
-    session->using_proxy = FALSE;
+    {
+      session->using_proxy = FALSE;
+    }
 
   /* Setup authentication. */
   SVN_ERR(load_http_auth_types(pool, config, server_group,
@@ -763,7 +802,7 @@ path_dirent_walker(void *baton,
     {
       const char *base_name;
 
-      entry = apr_pcalloc(pool, sizeof(*entry));
+      entry = svn_dirent_create(pool);
 
       apr_hash_set(dirents->full_paths, path, path_len, entry);
 
@@ -881,7 +920,7 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
         return svn_error_trace(err);
     }
 
-  dwb.entry = apr_pcalloc(pool, sizeof(*dwb.entry));
+  dwb.entry = svn_dirent_create(pool);
   dwb.supports_deadprop_count = &deadprop_count;
   dwb.result_pool = pool;
   SVN_ERR(svn_ra_serf__walk_node_props(props, dirent_walker, &dwb, pool));

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/update.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/update.c Mon Feb  4 20:48:05 2013
@@ -74,7 +74,8 @@ typedef enum report_state_e {
     ABSENT_FILE,
     PROP,
     IGNORE_PROP_NAME,
-    NEED_PROP_NAME
+    NEED_PROP_NAME,
+    TXDELTA
 } report_state_e;
 
 
@@ -228,6 +229,8 @@ typedef struct report_info_t
   const char *final_sha1_checksum;
   svn_txdelta_window_handler_t textdelta;
   void *textdelta_baton;
+  svn_stream_t *svndiff_decoder;
+  svn_stream_t *base64_decoder;
 
   /* Checksum for close_file */
   const char *final_checksum;
@@ -318,6 +321,9 @@ struct report_context_t {
   /* Do we want the server to send copyfrom args or not? */
   svn_boolean_t send_copyfrom_args;
 
+  /* Is the server sending everything in one response? */
+  svn_boolean_t send_all_mode;
+
   /* Is the server including properties inline for newly added
      files/dirs? */
   svn_boolean_t add_props_included;
@@ -357,6 +363,10 @@ struct report_context_t {
 
   /* completed PROPFIND requests (contains svn_ra_serf__handler_t) */
   svn_ra_serf__list_t *done_propfinds;
+  svn_ra_serf__list_t *done_dir_propfinds;
+
+  /* list of outstanding prop changes (contains report_dir_t) */
+  svn_ra_serf__list_t *active_dir_propfinds;
 
   /* list of files that only have prop changes (contains report_info_t) */
   svn_ra_serf__list_t *file_propchanges_only;
@@ -493,26 +503,42 @@ update_cdata(svn_ra_serf__xml_estate_t *
 static svn_ra_serf__connection_t *
 get_best_connection(report_context_t *ctx)
 {
-  svn_ra_serf__connection_t * conn;
-  int first_conn;
+  svn_ra_serf__connection_t *conn;
+  int first_conn = 1;
 
   /* Skip the first connection if the REPORT response hasn't been completely
-     received yet. */
-  first_conn = ctx->report_received ? 0: 1;
-
+     received yet or if we're being told to limit our connections to
+     2 (because this could be an attempt to ensure that we do all our
+     auxiliary GETs/PROPFINDs on a single connection).
+
+     ### FIXME: This latter requirement (max_connections > 2) is
+     ### really just a hack to work around the fact that some update
+     ### editor implementations (such as svnrdump's dump editor)
+     ### simply can't handle the way ra_serf violates the editor v1
+     ### drive ordering requirements.
+     ### 
+     ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+  */
+  if (ctx->report_received && (ctx->sess->max_connections > 2))
+    first_conn = 0;
+
+  /* Currently, we just cycle connections.  In the future we could
+     store the number of pending requests on each connection, or
+     perform other heuristics, to achieve better connection usage.
+     (As an optimization, if there's only one available auxiliary
+     connection to use, don't bother doing all the cur_conn math --
+     just return that one connection.)  */
   if (ctx->sess->num_conns - first_conn == 1)
-    return ctx->sess->conns[first_conn];
-
-  /* Currently just cycle connections. In future we could store number of
-   * pending requests on each connection for better connection usage. */
-  conn = ctx->sess->conns[ctx->sess->cur_conn];
-
-  /* Switch our connection. */
-  ctx->sess->cur_conn++;
-
-  if (ctx->sess->cur_conn >= ctx->sess->num_conns)
-      ctx->sess->cur_conn = first_conn;
-
+    {
+      conn = ctx->sess->conns[first_conn];
+    }
+  else
+    {
+      conn = ctx->sess->conns[ctx->sess->cur_conn];
+      ctx->sess->cur_conn++;
+      if (ctx->sess->cur_conn >= ctx->sess->num_conns)
+        ctx->sess->cur_conn = first_conn;
+    }
   return conn;
 }
 
@@ -909,7 +935,7 @@ cancel_fetch(serf_request_t *request,
        */
       if (fetch_ctx->read_headers)
         {
-          if (fetch_ctx->aborted_read == FALSE && fetch_ctx->read_size)
+          if (!fetch_ctx->aborted_read && fetch_ctx->read_size)
             {
               fetch_ctx->aborted_read = TRUE;
               fetch_ctx->aborted_read_size = fetch_ctx->read_size;
@@ -1063,7 +1089,7 @@ handle_fetch(serf_request_t *request,
   /* ### new field. make sure we didn't miss some initialization.  */
   SVN_ERR_ASSERT(fetch_ctx->handler != NULL);
 
-  if (fetch_ctx->read_headers == FALSE)
+  if (!fetch_ctx->read_headers)
     {
       serf_bucket_t *hdrs;
       const char *val;
@@ -1347,6 +1373,27 @@ maybe_close_dir_chain(report_dir_t *dir)
     {
       report_dir_t *parent = cur_dir->parent_dir;
       report_context_t *report_context = cur_dir->report_context;
+      svn_boolean_t propfind_in_done_list = FALSE;
+      svn_ra_serf__list_t *done_list;
+
+      /* Make sure there are no references to this dir in the
+         active_dir_propfinds list.  If there are, don't close the
+         directory -- which would delete the pool from which the
+         relevant active_dir_propfinds list item is allocated -- and
+         of course don't crawl upward to check the parents for
+         a closure opportunity, either.  */
+      done_list = report_context->active_dir_propfinds;
+      while (done_list)
+        {
+          if (done_list->data == cur_dir)
+            {
+              propfind_in_done_list = TRUE;
+              break;
+            }
+          done_list = done_list->next;
+        }
+      if (propfind_in_done_list)
+        break;
 
       SVN_ERR(close_dir(cur_dir));
       if (parent)
@@ -1377,6 +1424,10 @@ handle_propchange_only(report_info_t *in
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this file (and perhaps even
+     parents of that) can be closed now.  */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1401,6 +1452,10 @@ handle_local_content(report_info_t *info
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this fetched item (and
+     perhaps even parents of that) can be closed now. */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1415,17 +1470,6 @@ fetch_file(report_context_t *ctx, report
   /* What connection should we go on? */
   conn = get_best_connection(ctx);
 
-  /* go fetch info->name from DAV:checked-in */
-  info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
-                                        info->base_rev, "DAV:", "checked-in");
-
-  if (!info->url)
-    {
-      return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                              _("The REPORT or PROPFIND response did not "
-                                "include the requested checked-in value"));
-    }
-
   /* If needed, create the PROPFIND to retrieve the file's properties. */
   info->propfind_handler = NULL;
   if (info->fetch_props)
@@ -1565,12 +1609,7 @@ fetch_file(report_context_t *ctx, report
     }
   else
     {
-      /* No propfind or GET request.  Just handle the prop changes now.
-
-         Note: we'll use INFO->POOL for the scratch_pool here since it will
-         be destroyed at the end of handle_propchange_only(). That pool
-         would be quite fine, but it is unclear how long INFO->POOL will
-         stick around since its lifetime and usage are unclear.  */
+      /* No propfind or GET request.  Just handle the prop changes now. */
       SVN_ERR(handle_propchange_only(info, info->pool));
     }
 
@@ -1597,9 +1636,20 @@ start_report(svn_ra_serf__xml_parser_t *
 
   if (state == NONE && strcmp(name.name, "update-report") == 0)
     {
-      const char *val = svn_xml_get_attr_value("inline-props", attrs);
+      const char *val;
+
+      val = svn_xml_get_attr_value("inline-props", attrs);
       if (val && (strcmp(val, "true") == 0))
         ctx->add_props_included = TRUE;
+
+      val = svn_xml_get_attr_value("send-all", attrs);
+      if (val && (strcmp(val, "true") == 0))
+        {
+          ctx->send_all_mode = TRUE;
+
+          /* All properties are included in send-all mode. */
+          ctx->add_props_included = TRUE;
+        }
     }
   else if (state == NONE && strcmp(name.name, "target-revision") == 0)
     {
@@ -1802,7 +1852,11 @@ start_report(svn_ra_serf__xml_parser_t *
       info = push_state(parser, ctx, ADD_FILE);
 
       info->base_rev = SVN_INVALID_REVNUM;
-      info->fetch_file = TRUE;
+
+      /* If the server isn't in "send-all" mode, we should expect to
+         fetch contents for added files. */
+      if (! ctx->send_all_mode)
+        info->fetch_file = TRUE;
 
       /* If the server isn't included properties for added items,
          we'll need to fetch them ourselves. */
@@ -2042,7 +2096,31 @@ start_report(svn_ra_serf__xml_parser_t *
              addition to <fetch-file>s and such) when *not* in
              "send-all" mode.  As a client, we're smart enough to know
              that's wrong, so we'll just ignore these tags. */
-          ;
+          if (ctx->send_all_mode)
+            {
+              const svn_delta_editor_t *update_editor = ctx->update_editor;
+
+              info = push_state(parser, ctx, TXDELTA);
+
+              if (! info->file_baton)
+                {
+                  SVN_ERR(open_updated_file(info, FALSE, info->pool));
+                }
+
+              info->base_checksum = svn_xml_get_attr_value("base-checksum",
+                                                           attrs);
+              SVN_ERR(update_editor->apply_textdelta(info->file_baton,
+                                                     info->base_checksum,
+                                                     info->editor_pool,
+                                                     &info->textdelta,
+                                                     &info->textdelta_baton));
+              info->svndiff_decoder = svn_txdelta_parse_svndiff(
+                                          info->textdelta,
+                                          info->textdelta_baton,
+                                          TRUE, info->pool);
+              info->base64_decoder = svn_base64_decode(info->svndiff_decoder,
+                                                       info->pool);
+            }
         }
       else
         {
@@ -2126,13 +2204,15 @@ end_report(svn_ra_serf__xml_parser_t *pa
        */
       if (info->dir->fetch_props)
         {
+          svn_ra_serf__list_t *list_item;
+ 
           SVN_ERR(svn_ra_serf__deliver_props(&info->dir->propfind_handler,
                                              info->dir->props, ctx->sess,
                                              get_best_connection(ctx),
                                              info->dir->url,
                                              ctx->target_rev, "0",
                                              all_props,
-                                             &ctx->done_propfinds,
+                                             &ctx->done_dir_propfinds,
                                              info->dir->pool));
           SVN_ERR_ASSERT(info->dir->propfind_handler);
 
@@ -2141,6 +2221,11 @@ end_report(svn_ra_serf__xml_parser_t *pa
 
           ctx->num_active_propfinds++;
 
+          list_item = apr_pcalloc(info->dir->pool, sizeof(*list_item));
+          list_item->data = info->dir;
+          list_item->next = ctx->active_dir_propfinds;
+          ctx->active_dir_propfinds = list_item;
+
           if (ctx->num_active_fetches + ctx->num_active_propfinds
               > REQUEST_COUNT_TO_PAUSE)
             ctx->parser_ctx->paused = TRUE;
@@ -2150,6 +2235,12 @@ end_report(svn_ra_serf__xml_parser_t *pa
           info->dir->propfind_handler = NULL;
         }
 
+      /* See if this directory (and perhaps even parents of that) can
+         be closed now.  This is likely to be the case only if we
+         didn't need to contact the server for supplemental
+         information required to handle any of this directory's
+         children.  */
+      SVN_ERR(maybe_close_dir_chain(info->dir));
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == OPEN_FILE && strcmp(name.name, "open-file") == 0)
@@ -2166,7 +2257,7 @@ end_report(svn_ra_serf__xml_parser_t *pa
       info->lock_token = apr_hash_get(ctx->lock_path_tokens, info->name,
                                       APR_HASH_KEY_STRING);
 
-      if (info->lock_token && info->fetch_props == FALSE)
+      if (info->lock_token && !info->fetch_props)
         info->fetch_props = TRUE;
 
       /* If possible, we'd like to fetch only a delta against a
@@ -2223,13 +2314,89 @@ end_report(svn_ra_serf__xml_parser_t *pa
           info->delta_base = value ? value->data : NULL;
         }
 
-      SVN_ERR(fetch_file(ctx, info));
+      /* go fetch info->name from DAV:checked-in */
+      info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+                                            info->base_rev, "DAV:", "checked-in");
+      if (!info->url)
+        {
+          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+                                  _("The REPORT or PROPFIND response did not "
+                                    "include the requested checked-in value"));
+        }
+
+      /* If the server is in "send-all" mode, we might have opened the
+         file when we started seeing content for it.  If we didn't get
+         any content for it, we still need to open the file.  But in
+         any case, we can then immediately close it.  */
+      if (ctx->send_all_mode)
+        {
+          if (! info->file_baton)
+            {
+              SVN_ERR(open_updated_file(info, FALSE, info->pool));
+            }
+          SVN_ERR(close_updated_file(info, info->pool));
+          info->dir->ref_count--;
+        }
+      /* Otherwise, if the server is *not* in "send-all" mode, we
+         should be at a point where we can queue up any auxiliary
+         content-fetching requests.  */
+      else
+        {
+          SVN_ERR(fetch_file(ctx, info));
+        }
+
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == ADD_FILE && strcmp(name.name, "add-file") == 0)
     {
-      /* We should have everything we need to fetch the file. */
-      SVN_ERR(fetch_file(ctx, parser->state->private));
+      report_info_t *info = parser->state->private;
+
+      /* go fetch info->name from DAV:checked-in */
+      info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+                                            info->base_rev, "DAV:", "checked-in");
+      if (!info->url)
+        {
+          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+                                  _("The REPORT or PROPFIND response did not "
+                                    "include the requested checked-in value"));
+        }
+
+      /* If the server is in "send-all" mode, we might have opened the
+         file when we started seeing content for it.  If we didn't get
+         any content for it, we still need to open the file.  But in
+         any case, we can then immediately close it.  */
+      if (ctx->send_all_mode)
+        {
+          if (! info->file_baton)
+            {
+              SVN_ERR(open_updated_file(info, FALSE, info->pool));
+            }
+          SVN_ERR(close_updated_file(info, info->pool));
+          info->dir->ref_count--;
+        }
+      /* Otherwise, if the server is *not* in "send-all" mode, we
+         should be at a point where we can queue up any auxiliary
+         content-fetching requests.  */
+      else
+        {
+          SVN_ERR(fetch_file(ctx, info));
+        }
+
+      svn_ra_serf__xml_pop_state(parser);
+    }
+  else if (state == TXDELTA && strcmp(name.name, "txdelta") == 0)
+    {
+      report_info_t *info = parser->state->private;
+
+      /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+         <fetch-file>s and such) when *not* in "send-all" mode.  As a
+         client, we're smart enough to know that's wrong, so when not
+         in "receiving-all" mode, we'll ignore these tags. */
+      if (ctx->send_all_mode)
+        {
+          SVN_ERR(svn_stream_close(info->base64_decoder));
+        }
+
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == PROP)
@@ -2356,6 +2523,27 @@ cdata_report(svn_ra_serf__xml_parser_t *
 
       svn_stringbuf_appendbytes(info->prop_value, data, len);
     }
+  else if (parser->state->current_state == TXDELTA)
+    {
+      /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+         <fetch-file>s and such) when *not* in "send-all" mode.  As a
+         client, we're smart enough to know that's wrong, so when not
+         in "receiving-all" mode, we'll ignore these tags. */
+      if (ctx->send_all_mode)
+        {
+          apr_size_t nlen = len;
+          report_info_t *info = parser->state->private;
+
+          SVN_ERR(svn_stream_write(info->base64_decoder, data, &nlen));
+          if (nlen != len)
+            {
+              /* Short write without associated error?  "Can't happen." */
+              return svn_error_createf(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+                                       _("Error writing to '%s': unexpected EOF"),
+                                       info->name);
+            }
+        }
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2550,6 +2738,28 @@ create_update_report_body(serf_bucket_t 
   return SVN_NO_ERROR;
 }
 
+/* Serf callback to setup update request headers. */
+static svn_error_t *
+setup_update_report_headers(serf_bucket_t *headers,
+                            void *baton,
+                            apr_pool_t *pool)
+{
+  report_context_t *report = baton;
+
+  if (report->sess->using_compression)
+    {
+      serf_bucket_headers_setn(headers, "Accept-Encoding",
+                               "gzip;svndiff1;q=0.9,svndiff;q=0.8");
+    }
+  else
+    {
+      serf_bucket_headers_setn(headers, "Accept-Encoding",
+                               "svndiff1;q=0.9,svndiff;q=0.8");
+    }
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 finish_report(void *report_baton,
               apr_pool_t *pool)
@@ -2595,6 +2805,9 @@ finish_report(void *report_baton,
   handler->body_delegate = create_update_report_body;
   handler->body_delegate_baton = report;
   handler->body_type = "text/xml";
+  handler->custom_accept_encoding = TRUE;
+  handler->header_delegate = setup_update_report_headers;
+  handler->header_delegate_baton = report;
   handler->conn = sess->conns[0];
   handler->session = sess;
 
@@ -2691,14 +2904,16 @@ finish_report(void *report_baton,
         }
 
       /* Open extra connections if we have enough requests to send. */
-      if (sess->num_conns < MAX_NR_OF_CONNS)
+      if (sess->num_conns < sess->max_connections)
         SVN_ERR(open_connection_if_needed(sess, report->num_active_fetches +
                                           report->num_active_propfinds));
 
-      /* prune our propfind list if they are done. */
+      /* Prune completed file PROPFINDs. */
       done_list = report->done_propfinds;
       while (done_list)
         {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
           svn_pool_clear(iterpool_inner);
 
           report->num_active_propfinds--;
@@ -2733,39 +2948,46 @@ finish_report(void *report_baton,
                 {
                   report_info_t *info = cur->data;
 
-                  /* If we've got cached file content for this file,
-                     take care of the locally collected properties and
-                     file content at once.  Otherwise, just deal with
-                     the collected properties. */
-                  if (info->cached_contents)
+                  if (!prev)
                     {
-                      SVN_ERR(handle_local_content(info, iterpool_inner));
+                      report->file_propchanges_only = cur->next;
                     }
                   else
                     {
-                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
+                      prev->next = cur->next;
                     }
 
-                  if (!prev)
+                  /* If we've got cached file content for this file,
+                     take care of the locally collected properties and
+                     file content at once.  Otherwise, just deal with
+                     the collected properties.
+
+                     NOTE:  These functions below could delete
+                     info->dir->pool (via maybe_close_dir_chain()),
+                     from which is allocated the list item in
+                     report->file_propchanges_only.
+                  */
+                  if (info->cached_contents)
                     {
-                      report->file_propchanges_only = cur->next;
+                      SVN_ERR(handle_local_content(info, iterpool_inner));
                     }
                   else
                     {
-                      prev->next = cur->next;
+                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
                     }
                 }
             }
 
-          done_list = done_list->next;
+          done_list = next_done;
         }
       report->done_propfinds = NULL;
 
-      /* Prune completely fetches from our list. */
+      /* Prune completed fetches from our list. */
       done_list = report->done_fetches;
       while (done_list)
         {
           report_fetch_t *done_fetch = done_list->data;
+          svn_ra_serf__list_t *next_done = done_list->next;
           report_dir_t *cur_dir;
 
           /* Decrease the refcount in the parent directory of the file
@@ -2776,14 +2998,77 @@ finish_report(void *report_baton,
           /* Decrement our active fetch count. */
           report->num_active_fetches--;
 
-          done_list = done_list->next;
-
           /* See if the parent directory of this fetched item (and
-             perhaps even parents of that) can be closed now. */
+             perhaps even parents of that) can be closed now. 
+
+             NOTE:  This could delete cur_dir->pool, from which is
+             allocated the list item in report->done_fetches.
+          */
           SVN_ERR(maybe_close_dir_chain(cur_dir));
+
+          done_list = next_done;
         }
       report->done_fetches = NULL;
 
+      /* Prune completed directory PROPFINDs. */
+      done_list = report->done_dir_propfinds;
+      while (done_list)
+        {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
+          report->num_active_propfinds--;
+
+          if (report->active_dir_propfinds)
+            {
+              svn_ra_serf__list_t *cur, *prev;
+
+              prev = NULL;
+              cur = report->active_dir_propfinds;
+
+              while (cur)
+                {
+                  report_dir_t *item = cur->data;
+
+                  if (item->propfind_handler == done_list->data)
+                    {
+                      break;
+                    }
+
+                  prev = cur;
+                  cur = cur->next;
+                }
+              SVN_ERR_ASSERT(cur); /* we expect to find a matching propfind! */
+
+              /* If we found a match, set the new props and remove this
+               * propchange from our list.
+               */
+              if (cur)
+                {
+                  report_dir_t *cur_dir = cur->data;
+
+                  if (!prev)
+                    {
+                      report->active_dir_propfinds = cur->next;
+                    }
+                  else
+                    {
+                      prev->next = cur->next;
+                    }
+
+                  /* See if this directory (and perhaps even parents of that)
+                     can be closed now.
+
+                     NOTE:  This could delete cur_dir->pool, from which is
+                     allocated the list item in report->active_dir_propfinds.
+                  */
+                  SVN_ERR(maybe_close_dir_chain(cur_dir));
+                }
+            }
+
+          done_list = next_done;
+        }
+      report->done_dir_propfinds = NULL;
+
       /* If the parser is paused, and the number of active requests has
          dropped far enough, then resume parsing.  */
       if (parser_ctx->paused
@@ -2811,7 +3096,7 @@ finish_report(void *report_baton,
     {
       /* Ensure that we opened and closed our root dir and that we closed
        * all of our children. */
-      if (report->closed_root == FALSE && report->root_dir != NULL)
+      if (!report->closed_root && report->root_dir != NULL)
         {
           SVN_ERR(close_all_dirs(report->root_dir));
         }
@@ -2876,6 +3161,7 @@ make_update_reporter(svn_ra_session_t *r
   svn_boolean_t server_supports_depth;
   svn_ra_serf__session_t *sess = ra_session->priv;
   svn_stringbuf_t *buf = NULL;
+  svn_boolean_t use_bulk_updates;
 
   SVN_ERR(svn_ra_serf__has_capability(ra_session, &server_supports_depth,
                                       SVN_RA_CAPABILITY_DEPTH, scratch_pool));
@@ -2922,9 +3208,74 @@ make_update_reporter(svn_ra_session_t *r
                                    svn_io_file_del_on_pool_cleanup,
                                    report->pool, scratch_pool));
 
-  svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "S:update-report",
-                        "xmlns:S", SVN_XML_NAMESPACE,
-                        NULL);
+  if (sess->bulk_updates == svn_tristate_true)
+    {
+      /* User would like to use bulk updates. */
+      use_bulk_updates = TRUE;
+    }
+  else if (sess->bulk_updates == svn_tristate_false)
+    {
+      /* User doesn't want bulk updates. */
+      use_bulk_updates = FALSE;
+    }
+  else
+    {
+      /* User doesn't have any preferences on bulk updates. Decide on server
+         preferences and capabilities. */
+      if (sess->server_allows_bulk)
+        {
+          if (apr_strnatcasecmp(sess->server_allows_bulk, "off") == 0)
+            {
+              /* Server doesn't want bulk updates */
+              use_bulk_updates = FALSE;
+            }
+          else if (apr_strnatcasecmp(sess->server_allows_bulk, "prefer") == 0)
+            {
+              /* Server prefers bulk updates, and we respect that */
+              use_bulk_updates = TRUE;
+            }
+          else
+            {
+              /* Server allows bulk updates, but doesn't dictate its use. Do
+                 whatever is the default. */
+              use_bulk_updates = FALSE;
+            }
+        }
+      else
+        {
+          /* Pre-1.8 server didn't send the bulk_updates header. Check if server
+             supports inlining properties in update editor report. */
+          if (sess->supports_inline_props)
+            {
+              /* Inline props supported: do not use bulk updates. */
+              use_bulk_updates = FALSE;
+            }
+          else
+            {
+              /* Inline props are not supported: use bulk updates to avoid
+               * PROPFINDs for every added node. */
+              use_bulk_updates = TRUE;
+            }
+        }
+    }
+
+  if (use_bulk_updates)
+    {
+      svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+                            "S:update-report",
+                            "xmlns:S", SVN_XML_NAMESPACE, "send-all", "true",
+                            NULL);
+    }
+  else
+    {
+      svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+                            "S:update-report",
+                            "xmlns:S", SVN_XML_NAMESPACE,
+                            NULL);
+      /* Subversion 1.8+ servers can be told to send properties for newly
+         added items inline even when doing a skelta response. */
+      make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+    }
 
   make_simple_xml_tag(&buf, "S:src-path", report->source, scratch_pool);
 
@@ -2963,9 +3314,20 @@ make_update_reporter(svn_ra_session_t *r
       make_simple_xml_tag(&buf, "S:recursive", "no", scratch_pool);
     }
 
-  /* Subversion 1.8+ servers can be told to send properties for newly
-     added items inline even when doing a skelta response. */
-  make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+  /* When in 'send-all' mode, mod_dav_svn will assume that it should
+     calculate and transmit real text-deltas (instead of empty windows
+     that merely indicate "text is changed") unless it finds this
+     element.
+
+     NOTE: Do NOT count on servers actually obeying this, as some exist
+     which obey send-all, but do not check for this directive at all!
+
+     NOTE 2: When not in 'send-all' mode, mod_dav_svn can still be configured to
+     override our request and send text-deltas. */
+  if (! text_deltas)
+    {
+      make_simple_xml_tag(&buf, "S:text-deltas", "no", scratch_pool);
+    }
 
   make_simple_xml_tag(&buf, "S:depth", svn_depth_to_word(depth), scratch_pool);
 
@@ -3123,7 +3485,9 @@ try_get_wc_contents(svn_boolean_t *found
   
   if (wc_stream)
     {
-      SVN_ERR(svn_stream_copy3(wc_stream, dst_stream, NULL, NULL, pool));
+        SVN_ERR(svn_stream_copy3(wc_stream,
+                                 svn_stream_disown(dst_stream, pool),
+                                 NULL, NULL, pool));
       *found_p = TRUE;
     }
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/util.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/util.c Mon Feb  4 20:48:05 2013
@@ -1559,7 +1559,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
     }
 
   /* Woo-hoo.  Nothing here to see.  */
-  if (sl.code == 404 && ctx->ignore_errors == FALSE)
+  if (sl.code == 404 && !ctx->ignore_errors)
     {
       err = handle_server_error(request, response, pool);
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/client.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/client.c Mon Feb  4 20:48:05 2013
@@ -1274,7 +1274,7 @@ static svn_error_t *ra_svn_get_dir(svn_r
                                      &name, &kind, &size, &has_props,
                                      &crev, &cdate, &cauthor));
       name = svn_relpath_canonicalize(name, pool);
-      dirent = apr_palloc(pool, sizeof(*dirent));
+      dirent = svn_dirent_create(pool);
       dirent->kind = svn_node_kind_from_word(kind);
       dirent->size = size;/* FIXME: svn_filesize_t */
       dirent->has_props = has_props;
@@ -1304,7 +1304,7 @@ static svn_error_t *ra_svn_get_dir(svn_r
 static svn_tristate_t
 optbool_to_tristate(apr_uint64_t v)
 {
-  if (v == TRUE)
+  if (v == TRUE)  /* not just non-zero but exactly equal to 'TRUE' */
     return svn_tristate_true;
   if (v == FALSE)
     return svn_tristate_false;
@@ -1748,7 +1748,7 @@ static svn_error_t *ra_svn_stat(svn_ra_s
                                      &kind, &size, &has_props,
                                      &crev, &cdate, &cauthor));
 
-      the_dirent = apr_palloc(pool, sizeof(*the_dirent));
+      the_dirent = svn_dirent_create(pool);
       the_dirent->kind = svn_node_kind_from_word(kind);
       the_dirent->size = size;/* FIXME: svn_filesize_t */
       the_dirent->has_props = has_props;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/cyrus_auth.c Mon Feb  4 20:48:05 2013
@@ -179,7 +179,7 @@ svn_ra_svn__sasl_common_init(apr_pool_t 
                  sasl_mutex_unlock_cb,
                  sasl_mutex_free_cb);
   free_mutexes = apr_array_make(sasl_pool, 0, sizeof(svn_mutex__t *));
-  return svn_mutex__init(&array_mutex, TRUE, sasl_pool);
+  SVN_ERR(svn_mutex__init(&array_mutex, TRUE, sasl_pool));
 
 #endif /* APR_HAS_THREADS */
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/editorp.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/editorp.c Mon Feb  4 20:48:05 2013
@@ -39,6 +39,7 @@
 #include "svn_private_config.h"
 
 #include "private/svn_fspath.h"
+#include "private/svn_editor.h"
 
 #include "ra_svn.h"
 
@@ -975,7 +976,7 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
           else
             {
               err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
-                                      _("Unknown command '%s'"), cmd);
+                                      _("Unknown editor command '%s'"), cmd);
               err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
             }
         }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/marshal.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_svn/marshal.c Mon Feb  4 20:48:05 2013
@@ -1799,7 +1799,7 @@ svn_error_t *svn_ra_svn_handle_commands2
       else
         {
           err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
-                                  _("Unknown command '%s'"), cmdname);
+                                  _("Unknown editor command '%s'"), cmdname);
           err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
         }