You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by iv...@apache.org on 2015/09/11 17:51:34 UTC

svn commit: r1702504 [13/19] - in /subversion/branches/reuse-ra-session: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ subversion/bindings/ctypes-python/csvn/ext/ subversion/bindings/javahl/native/ ...

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/rev_hunt.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/rev_hunt.c Fri Sep 11 15:51:30 2015
@@ -710,23 +710,6 @@ svn_repos_trace_node_locations(svn_fs_t
       if (! prev_path)
         break;
 
-      if (authz_read_func)
-        {
-          svn_boolean_t readable;
-          svn_fs_root_t *tmp_root;
-
-          SVN_ERR(svn_fs_revision_root(&tmp_root, fs, revision, currpool));
-          SVN_ERR(authz_read_func(&readable, tmp_root, path,
-                                  authz_read_baton, currpool));
-          if (! readable)
-            {
-              svn_pool_destroy(lastpool);
-              svn_pool_destroy(currpool);
-
-              return SVN_NO_ERROR;
-            }
-        }
-
       /* Assign the current path to all younger revisions until we reach
          the copy target rev. */
       while ((revision_ptr < revision_ptr_end)
@@ -749,6 +732,20 @@ svn_repos_trace_node_locations(svn_fs_t
       path = prev_path;
       revision = prev_rev;
 
+      if (authz_read_func)
+        {
+          svn_boolean_t readable;
+          SVN_ERR(svn_fs_revision_root(&root, fs, revision, currpool));
+          SVN_ERR(authz_read_func(&readable, root, path,
+                                  authz_read_baton, currpool));
+          if (!readable)
+            {
+              svn_pool_destroy(lastpool);
+              svn_pool_destroy(currpool);
+              return SVN_NO_ERROR;
+            }
+        }
+
       /* Clear last pool and switch. */
       svn_pool_clear(lastpool);
       tmppool = lastpool;
@@ -1336,6 +1333,7 @@ struct send_baton
   apr_hash_t *last_props;
   const char *last_path;
   svn_fs_root_t *last_root;
+  svn_boolean_t include_merged_revisions;
 };
 
 /* Send PATH_REV to HANDLER and HANDLER_BATON, using information provided by
@@ -1373,15 +1371,32 @@ send_path_revision(struct path_revision
   SVN_ERR(svn_prop_diffs(&prop_diffs, props, sb->last_props,
                          sb->iterpool));
 
-  /* Check if the contents *may* have changed. (Allow false positives,
-     for now, as the blame implementation currently depends on them.) */
-  /* Special case: In the first revision, we always provide a delta. */
-  if (sb->last_root)
-    SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
-                                      sb->last_path, root, path_rev->path,
-                                      sb->iterpool));
+  /* Check if the contents *may* have changed. */
+  if (! sb->last_root)
+    {
+      /* Special case: In the first revision, we always provide a delta. */
+      contents_changed = TRUE;
+    }
+  else if (sb->include_merged_revisions
+           && strcmp(sb->last_path, path_rev->path))
+    {
+      /* ### This is a HACK!!!
+       * Blame -g, in older clients anyways, relies on getting a notification
+       * whenever the path changes - even if there was no content change.
+       *
+       * TODO: A future release should take an extra parameter and depending
+       * on that either always send a text delta or only send it if there
+       * is a difference. */
+      contents_changed = TRUE;
+    }
   else
-    contents_changed = TRUE;
+    {
+      /* Did the file contents actually change?
+       * It could e.g. be a property-only change. */
+      SVN_ERR(svn_fs_contents_different(&contents_changed, sb->last_root,
+                                        sb->last_path, root, path_rev->path,
+                                        sb->iterpool));
+    }
 
   /* We have all we need, give to the handler. */
   SVN_ERR(handler(handler_baton, path_rev->path, path_rev->revnum,
@@ -1450,6 +1465,7 @@ get_file_revs_backwards(svn_repos_t *rep
   last_pool = svn_pool_create(scratch_pool);
   sb.iterpool = svn_pool_create(scratch_pool);
   sb.last_pool = svn_pool_create(scratch_pool);
+  sb.include_merged_revisions = FALSE;
 
   /* We want the first txdelta to be against the empty file. */
   sb.last_root = NULL;
@@ -1605,6 +1621,9 @@ svn_repos_get_file_revs2(svn_repos_t *re
   /* Create an empty hash table for the first property diff. */
   sb.last_props = apr_hash_make(sb.last_pool);
 
+  /* Inform send_path_revision() whether workarounds / special behavior
+   * may be needed. */
+  sb.include_merged_revisions = include_merged_revisions;
 
   /* Get the revisions we are interested in. */
   duplicate_path_revs = apr_hash_make(scratch_pool);

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/atomic.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/atomic.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/atomic.c Fri Sep 11 15:51:30 2015
@@ -24,6 +24,7 @@
 #include <apr_time.h>
 #include "private/svn_atomic.h"
 
+
 /* Magic values for atomic initialization */
 #define SVN_ATOMIC_UNINITIALIZED 0
 #define SVN_ATOMIC_START_INIT    1
@@ -31,19 +32,20 @@
 #define SVN_ATOMIC_INITIALIZED   3
 
 
+/* Baton used by init_funct_t and init_once(). */
+typedef struct init_baton_t init_baton_t;
+
+/* Initialization function wrapper. Hides API details from init_once().
+   The implementation must return FALSE on failure. */
+typedef svn_boolean_t (*init_func_t)(init_baton_t *init_baton);
+
 /*
- * This is the actual atomic initialization driver.  The caller must
- * provide either ERR_INIT_FUNC and ERR_P, or STR_INIT_FUNC and
- * ERRSTR_P, but never both.
+ * This is the actual atomic initialization driver.
+ * Returns FALSE on failure.
  */
-static void
-init_once(svn_atomic__err_init_func_t err_init_func,
-          svn_error_t **err_p,
-          svn_atomic__str_init_func_t str_init_func,
-          const char **errstr_p,
-          volatile svn_atomic_t *global_status,
-          void *baton,
-          apr_pool_t* pool)
+static svn_boolean_t
+init_once(volatile svn_atomic_t *global_status,
+          init_func_t init_func, init_baton_t *init_baton)
 {
   /* !! Don't use localizable strings in this function, because these
      !! might cause deadlocks. This function can be used to initialize
@@ -53,44 +55,25 @@ init_once(svn_atomic__err_init_func_t er
      doesn't have statically-initialized mutexes, we implement a poor
      man's spinlock using svn_atomic_cas. */
 
-  svn_error_t *err = SVN_NO_ERROR;
-  const char *errstr = NULL;
   svn_atomic_t status = svn_atomic_cas(global_status,
                                        SVN_ATOMIC_START_INIT,
                                        SVN_ATOMIC_UNINITIALIZED);
 
-#ifdef SVN_DEBUG
-  /* Check that the parameters are valid. */
-  assert(!err_init_func != !str_init_func);
-  assert(!err_init_func == !err_p);
-  assert(!str_init_func == !errstr_p);
-#endif /* SVN_DEBUG */
-
   for (;;)
     {
       switch (status)
         {
         case SVN_ATOMIC_UNINITIALIZED:
-          if (err_init_func)
-            err = err_init_func(baton, pool);
-          else
-            errstr = str_init_func(baton);
-          if (err || errstr)
-            {
-              status = svn_atomic_cas(global_status,
-                                      SVN_ATOMIC_INIT_FAILED,
-                                      SVN_ATOMIC_START_INIT);
-            }
-          else
-            {
-              status = svn_atomic_cas(global_status,
-                                      SVN_ATOMIC_INITIALIZED,
-                                      SVN_ATOMIC_START_INIT);
-            }
-
-          /* Take another spin through the switch to report either
-             failure or success. */
-          continue;
+          {
+            const svn_boolean_t result = init_func(init_baton);
+            const svn_atomic_t init_state = (result
+                                             ? SVN_ATOMIC_INITIALIZED
+                                             : SVN_ATOMIC_INIT_FAILED);
+
+            svn_atomic_cas(global_status, init_state,
+                           SVN_ATOMIC_START_INIT);
+            return result;
+          }
 
         case SVN_ATOMIC_START_INIT:
           /* Wait for the init function to complete. */
@@ -101,19 +84,10 @@ init_once(svn_atomic__err_init_func_t er
           continue;
 
         case SVN_ATOMIC_INIT_FAILED:
-          if (err_init_func)
-            *err_p = svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err,
-                                      "Couldn't perform atomic initialization");
-          else
-            *errstr_p = errstr;
-          return;
+          return FALSE;
 
         case SVN_ATOMIC_INITIALIZED:
-          if (err_init_func)
-            *err_p = SVN_NO_ERROR;
-          else
-            *errstr_p = NULL;
-          return;
+          return TRUE;
 
         default:
           /* Something went seriously wrong with the atomic operations. */
@@ -123,15 +97,61 @@ init_once(svn_atomic__err_init_func_t er
 }
 
 
+/* This baton structure is used by the two flavours of init-once APIs
+   to hide their differences from the init_once() driver. Each private
+   API uses only selected parts of the baton.
+
+   No part of this structure changes unless a wrapped init function is
+   actually invoked by init_once().
+*/
+struct init_baton_t
+{
+  /* Used only by svn_atomic__init_once()/err_init_func_wrapper() */
+  svn_atomic__err_init_func_t err_init_func;
+  svn_error_t *err;
+  apr_pool_t *pool;
+
+  /* Used only by svn_atomic__init_no_error()/str_init_func_wrapper() */
+  svn_atomic__str_init_func_t str_init_func;
+  const char *errstr;
+
+  /* Used by both pairs of functions */
+  void *baton;
+};
+
+/* Wrapper for the svn_atomic__init_once init function. */
+static svn_boolean_t err_init_func_wrapper(init_baton_t *init_baton)
+{
+  init_baton->err = init_baton->err_init_func(init_baton->baton,
+                                              init_baton->pool);
+  return (init_baton->err == SVN_NO_ERROR);
+}
+
 svn_error_t *
 svn_atomic__init_once(volatile svn_atomic_t *global_status,
                       svn_atomic__err_init_func_t err_init_func,
                       void *baton,
                       apr_pool_t* pool)
 {
-  svn_error_t *err;
-  init_once(err_init_func, &err, NULL, NULL, global_status, baton, pool);
-  return err;
+  init_baton_t init_baton;
+  init_baton.err_init_func = err_init_func;
+  init_baton.err = NULL;
+  init_baton.pool = pool;
+  init_baton.baton = baton;
+
+  if (init_once(global_status, err_init_func_wrapper, &init_baton))
+    return SVN_NO_ERROR;
+
+  return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, init_baton.err,
+                          "Couldn't perform atomic initialization");
+}
+
+
+/* Wrapper for the svn_atomic__init_no_error init function. */
+static svn_boolean_t str_init_func_wrapper(init_baton_t *init_baton)
+{
+  init_baton->errstr = init_baton->str_init_func(init_baton->baton);
+  return (init_baton->errstr == NULL);
 }
 
 const char *
@@ -139,7 +159,18 @@ svn_atomic__init_once_no_error(volatile
                                svn_atomic__str_init_func_t str_init_func,
                                void *baton)
 {
-  const char *errstr;
-  init_once(NULL, NULL, str_init_func, &errstr, global_status, baton, NULL);
-  return errstr;
+  init_baton_t init_baton;
+  init_baton.str_init_func = str_init_func;
+  init_baton.errstr = NULL;
+  init_baton.baton = baton;
+
+  if (init_once(global_status, str_init_func_wrapper, &init_baton))
+    return NULL;
+
+  /* Our init function wrapper may not have been called; make sure
+     that we return generic error message in that case. */
+  if (!init_baton.errstr)
+    return "Couldn't perform atomic initialization";
+  else
+    return init_baton.errstr;
 }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/auth.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/auth.c Fri Sep 11 15:51:30 2015
@@ -880,3 +880,33 @@ svn_auth__make_session_auth(svn_auth_bat
 
   return SVN_NO_ERROR;
 }
+
+
+static svn_error_t *
+dummy_first_creds(void **credentials,
+                  void **iter_baton,
+                  void *provider_baton,
+                  apr_hash_t *parameters,
+                  const char *realmstring,
+                  apr_pool_t *pool)
+{
+  *credentials = NULL;
+  *iter_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+void
+svn_auth__get_dummmy_simple_provider(svn_auth_provider_object_t **provider,
+                                     apr_pool_t *pool)
+{
+  static const svn_auth_provider_t vtable = {
+    SVN_AUTH_CRED_SIMPLE,
+    dummy_first_creds,
+    NULL, NULL
+  };
+
+  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+  po->vtable = &vtable;
+  *provider = po;
+}

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

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/cache-membuffer.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/cache-membuffer.c Fri Sep 11 15:51:30 2015
@@ -28,12 +28,14 @@
 #include "svn_pools.h"
 #include "svn_checksum.h"
 #include "svn_private_config.h"
+#include "svn_hash.h"
 #include "svn_string.h"
 #include "svn_sorts.h"  /* get the MIN macro */
 
 #include "private/svn_atomic.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_mutex.h"
+#include "private/svn_subr_private.h"
 #include "private/svn_string_private.h"
 
 #include "cache.h"
@@ -117,6 +119,12 @@
  * key length stored in the entry acts as an additional offset to find the
  * actual item.
  *
+ * Most keys are 16 bytes or less.  We use the prefix indexes returned by
+ * a prefix_pool_t instance to uniquely identify the prefix in that case.
+ * Then the combination of prefix index and key stored in the fingerprint
+ * is then unique, too, and can never conflict.  No full key construction,
+ * storage and comparison is needed in that case.
+ *
  * All access to the cached data needs to be serialized. Because we want
  * to scale well despite that bottleneck, we simply segment the cache into
  * a number of independent caches (segments). Items will be multiplexed based
@@ -189,6 +197,10 @@
  * entries with the same entry key. However unlikely, though, two different
  * full keys (see full_key_t) may have the same entry key.  That is a
  * collision and at most one of them can be stored in the cache at any time.
+ *
+ * If the prefix is shared, which implies that the variable key part is no
+ * longer than 16 bytes, then there is a 1:1 mapping between full key and
+ * entry key.
  */
 typedef struct entry_key_t
 {
@@ -196,24 +208,184 @@ typedef struct entry_key_t
   apr_uint64_t fingerprint[2];
 
   /* Length of the full key.  This value is aligned to ITEM_ALIGNMENT to
-   * make sure the subsequent item content is properly aligned. */
+   * make sure the subsequent item content is properly aligned.  If 0,
+   * PREFIX_KEY is implied to be != NO_INDEX. */
   apr_size_t key_len;
+
+  /* Unique index of the shared key prefix, i.e. it's index within the
+   * prefix pool (see prefix_pool_t).  NO_INDEX if the key prefix is not
+   * shared, otherwise KEY_LEN==0 is implied. */
+  apr_uint32_t prefix_idx;
 } entry_key_t;
 
 /* A full key, i.e. the combination of the cache's key prefix with some
  * dynamic part appended to it.  It also contains its ENTRY_KEY.
+ *
+ * If the ENTRY_KEY has a 1:1 mapping to the FULL_KEY, then the latter
+ * will be empty and remains unused.
  */
 typedef struct full_key_t
 {
   /* Reduced form identifying the cache entry (if such an entry exists). */
   entry_key_t entry_key;
 
-  /* This contains the full combination.  Note that the SIZE element may
-   * be larger than ENTRY_KEY.KEY_LEN, but only the latter determines the
-   * valid key size. */
+  /* If ENTRY_KEY is not a 1:1 mapping of the prefix + dynamic key
+   * combination,  then this contains the full combination.  Note that the
+   * SIZE element may be larger than ENTRY_KEY.KEY_LEN, but only the latter
+   * determines the valid key size. */
   svn_membuf_t full_key;
 } full_key_t;
 
+/* A limited capacity, thread-safe pool of unique C strings.  Operations on
+ * this data structure are defined by prefix_pool_* functions.  The only
+ * "public" member is VALUES (r/o access only).
+ */
+typedef struct prefix_pool_t
+{
+  /* Map C string to a pointer into VALUES with the same contents. */
+  apr_hash_t *map;
+
+  /* Pointer to an array of strings. These are the contents of this pool
+   * and each one of them is referenced by MAP.  Valid indexes are 0 to
+   * VALUES_USED - 1.  May be NULL if VALUES_MAX is 0. */
+  const char **values;
+
+  /* Number of used entries that VALUES may have. */
+  apr_uint32_t values_max;
+
+  /* Number of used entries in VALUES.  Never exceeds VALUES_MAX. */
+  apr_uint32_t values_used;
+
+  /* Maximum number of bytes to allocate. */
+  apr_size_t bytes_max;
+
+  /* Number of bytes currently allocated.  Should not exceed BYTES_MAX but
+   * the implementation may . */
+  apr_size_t bytes_used;
+
+  /* The serialization object. */
+  svn_mutex__t *mutex;
+} prefix_pool_t;
+
+/* Set *PREFIX_POOL to a new instance that tries to limit allocation to
+ * BYTES_MAX bytes.  If MUTEX_REQUIRED is set and multi-threading is
+ * supported, serialize all access to the new instance.  Allocate the
+ * object from *RESULT_POOL. */
+static svn_error_t *
+prefix_pool_create(prefix_pool_t **prefix_pool,
+                   apr_size_t bytes_max,
+                   svn_boolean_t mutex_required,
+                   apr_pool_t *result_pool)
+{
+  enum
+    {
+      /* With 56 byes of overhead under 64 bits, we will probably never get
+       * substantially below this.  If we accidentally do, we will simply
+       * run out of entries in the VALUES array before running out of
+       * allocated memory. */
+      ESTIMATED_BYTES_PER_ENTRY = 120,
+    };
+
+  /* Number of entries we are going to support. */
+  apr_size_t capacity = MIN(APR_UINT32_MAX,
+                            bytes_max / ESTIMATED_BYTES_PER_ENTRY);
+
+  /* Construct the result struct. */
+  prefix_pool_t *result = apr_pcalloc(result_pool, sizeof(*result));
+  result->map = svn_hash__make(result_pool);
+
+  result->values = capacity
+                 ? apr_pcalloc(result_pool, capacity * sizeof(const char *))
+                 : NULL;
+  result->values_max = (apr_uint32_t)capacity;
+  result->values_used = 0;
+
+  result->bytes_max = bytes_max;
+  result->bytes_used = capacity * sizeof(svn_membuf_t);
+
+  SVN_ERR(svn_mutex__init(&result->mutex, mutex_required, result_pool));
+
+  /* Done. */
+  *prefix_pool = result;
+  return SVN_NO_ERROR;
+}
+
+/* Set *PREFIX_IDX to the offset in PREFIX_POOL->VALUES that contains the
+ * value PREFIX.  If none exists, auto-insert it.  If we can't due to
+ * capacity exhaustion, set *PREFIX_IDX to NO_INDEX.
+ * To be called by prefix_pool_get() only. */
+static svn_error_t *
+prefix_pool_get_internal(apr_uint32_t *prefix_idx,
+                         prefix_pool_t *prefix_pool,
+                         const char *prefix)
+{
+  enum
+    {
+      /* Size of an hash entry plus (max.) APR alignment loss.
+       *
+       * This may be slightly off if e.g. APR changes its internal data
+       * structures but that will translate in just a few percent (~10%)
+       * over-allocation.  Memory consumption will still be capped.
+       */
+      OVERHEAD = 40 + 8
+    };
+
+  const char **value;
+  apr_size_t prefix_len = strlen(prefix);
+  apr_size_t bytes_needed;
+  apr_pool_t *pool;
+
+  /* Lookup.  If we already know that prefix, return its index. */
+  value = apr_hash_get(prefix_pool->map, prefix, prefix_len);
+  if (value != NULL)
+    {
+      const apr_size_t index = value - prefix_pool->values;
+      SVN_ERR_ASSERT(index < prefix_pool->values_used);
+      *prefix_idx = (apr_uint32_t) index;
+      return SVN_NO_ERROR;
+    }
+
+  /* Capacity checks. */
+  if (prefix_pool->values_used == prefix_pool->values_max)
+    {
+      *prefix_idx = NO_INDEX;
+      return SVN_NO_ERROR;
+    }
+
+  bytes_needed = prefix_len + 1 + OVERHEAD;
+  if (prefix_pool->bytes_used + bytes_needed > prefix_pool->values_max)
+    {
+      *prefix_idx = NO_INDEX;
+      return SVN_NO_ERROR;
+    }
+
+  /* Add new entry. */
+  pool = apr_hash_pool_get(prefix_pool->map);
+
+  value = &prefix_pool->values[prefix_pool->values_used];
+  *value = apr_pstrndup(pool, prefix, prefix_len + 1);
+  apr_hash_set(prefix_pool->map, *value, prefix_len, value);
+
+  *prefix_idx = prefix_pool->values_used;
+  ++prefix_pool->values_used;
+  prefix_pool->bytes_used += bytes_needed;
+
+  return SVN_NO_ERROR;
+}
+
+/* Thread-safe wrapper around prefix_pool_get_internal. */
+static svn_error_t *
+prefix_pool_get(apr_uint32_t *prefix_idx,
+                prefix_pool_t *prefix_pool,
+                const char *prefix)
+{
+  SVN_MUTEX__WITH_LOCK(prefix_pool->mutex,
+                       prefix_pool_get_internal(prefix_idx, prefix_pool,
+                                                prefix));
+
+  return SVN_NO_ERROR;
+}
+
 /* Debugging / corruption detection support.
  * If you define this macro, the getter functions will performed expensive
  * checks on the item data, requested keys and entry types. If there is
@@ -263,13 +435,12 @@ typedef struct entry_tag_t
 /* Initialize all members of TAG except for the content hash.
  */
 static svn_error_t *store_key_part(entry_tag_t *tag,
-                                   const full_key_t *prefix_key,
+                                   const char *prefix,
                                    const void *key,
                                    apr_size_t key_len,
-                                   apr_pool_t *pool)
+                                   apr_pool_t *scratch_pool)
 {
   svn_checksum_t *checksum;
-  const char *prefix = prefix_key->full_key.data;
   apr_size_t prefix_len = strlen(prefix);
 
   if (prefix_len > sizeof(tag->prefix_tail))
@@ -280,12 +451,16 @@ static svn_error_t *store_key_part(entry
 
   SVN_ERR(svn_checksum(&checksum,
                        svn_checksum_md5,
+                       prefix,
+                       strlen(prefix),
+                       scratch_pool));
+  memcpy(tag->prefix_hash, checksum->digest, sizeof(tag->prefix_hash));
+
+  SVN_ERR(svn_checksum(&checksum,
+                       svn_checksum_md5,
                        key,
                        key_len,
-                       pool));
-
-  memcpy(tag->prefix_hash, prefix_key->entry_key.fingerprint,
-         sizeof(tag->prefix_hash));
+                       scratch_pool));
   memcpy(tag->key_hash, checksum->digest, sizeof(tag->key_hash));
 
   memset(tag->prefix_tail, 0, sizeof(tag->key_hash));
@@ -346,7 +521,7 @@ static svn_error_t* assert_equal_tags(co
   entry_tag_t *tag = &_tag;                                      \
   if (key)                                                       \
     SVN_ERR(store_key_part(tag,                                  \
-                           &cache->prefix,                       \
+                           get_prefix_key(cache),                \
                            key,                                  \
                            cache->key_len == APR_HASH_KEY_STRING \
                                ? strlen((const char *) key)      \
@@ -521,6 +696,12 @@ struct svn_membuffer_t
      and that all segments must / will report the same values here. */
   apr_uint32_t segment_count;
 
+  /* Collection of prefixes shared among all instances accessing the
+   * same membuffer cache backend.  If a prefix is contained in this
+   * pool then all cache instances using an equal prefix must actually
+   * use the one stored in this pool. */
+  prefix_pool_t *prefix_pool;
+
   /* The dictionary, GROUP_SIZE * (group_count + spare_group_count)
    * entries long.  Never NULL.
    */
@@ -802,8 +983,8 @@ initialize_group(svn_membuffer_t *cache,
   apr_uint32_t first_index =
       (group_index / GROUP_INIT_GRANULARITY) * GROUP_INIT_GRANULARITY;
   apr_uint32_t last_index = first_index + GROUP_INIT_GRANULARITY;
-  if (last_index > cache->group_count)
-    last_index = cache->group_count;
+  if (last_index > cache->group_count + cache->spare_group_count)
+    last_index = cache->group_count + cache->spare_group_count;
 
   for (i = first_index; i < last_index; ++i)
     {
@@ -1186,6 +1367,7 @@ entry_keys_match(const entry_key_t *lhs,
 {
   return (lhs->fingerprint[0] == rhs->fingerprint[0])
       && (lhs->fingerprint[1] == rhs->fingerprint[1])
+      && (lhs->prefix_idx == rhs->prefix_idx)
       && (lhs->key_len == rhs->key_len);
 }
 
@@ -1248,7 +1430,8 @@ find_entry(svn_membuffer_t *cache,
             /* If we want to preserve it, check that it is actual a match. */
             if (!find_empty)
               {
-                /* If there is no full key to compare, we are done. */
+                /* If the full key is fully defined in prefix_id & mangeled
+                 * key, we are done. */
                 if (!entry->key.key_len)
                   return entry;
 
@@ -1347,7 +1530,7 @@ find_entry(svn_membuffer_t *cache,
            */
           for (i = 0; i < GROUP_SIZE; ++i)
             if (entry != &to_shrink->entries[i])
-              let_entry_age(cache, entry);
+              let_entry_age(cache, &to_shrink->entries[i]);
 
           drop_entry(cache, entry);
         }
@@ -1675,6 +1858,7 @@ svn_cache__membuffer_cache_create(svn_me
                                   apr_pool_t *pool)
 {
   svn_membuffer_t *c;
+  prefix_pool_t *prefix_pool;
 
   apr_uint32_t seg;
   apr_uint32_t group_count;
@@ -1684,6 +1868,12 @@ svn_cache__membuffer_cache_create(svn_me
   apr_uint64_t data_size;
   apr_uint64_t max_entry_size;
 
+  /* Allocate 1% of the cache capacity to the prefix string pool.
+   */
+  SVN_ERR(prefix_pool_create(&prefix_pool, total_size / 100, thread_safe,
+                             pool));
+  total_size -= total_size / 100;
+
   /* Limit the total size (only relevant if we can address > 4GB)
    */
 #if APR_SIZEOF_VOIDP > 4
@@ -1794,14 +1984,18 @@ svn_cache__membuffer_cache_create(svn_me
       /* allocate buffers and initialize cache members
        */
       c[seg].segment_count = (apr_uint32_t)segment_count;
+      c[seg].prefix_pool = prefix_pool;
 
       c[seg].group_count = main_group_count;
       c[seg].spare_group_count = spare_group_count;
       c[seg].first_spare_group = NO_INDEX;
       c[seg].max_spare_used = 0;
 
-      c[seg].directory = apr_pcalloc(pool,
-                                     group_count * sizeof(entry_group_t));
+      /* Allocate but don't clear / zero the directory because it would add
+         significantly to the server start-up time if the caches are large.
+         Group initialization will take care of that in stead. */
+      c[seg].directory = apr_palloc(pool,
+                                    group_count * sizeof(entry_group_t));
 
       /* Allocate and initialize directory entries as "not initialized",
          hence "unused" */
@@ -2233,7 +2427,7 @@ membuffer_cache_get_internal(svn_membuff
 
 /* Look for the *ITEM identified by KEY. If no item has been stored
  * for KEY, *ITEM will be NULL. Otherwise, the DESERIALIZER is called
- * re-construct the proper object from the serialized data.
+ * to re-construct the proper object from the serialized data.
  * Allocations will be done in POOL.
  */
 static svn_error_t *
@@ -2581,11 +2775,11 @@ typedef struct svn_membuffer_cache_t
    */
   svn_cache__deserialize_func_t deserializer;
 
-  /* Prepend this byte sequence to any key passed to us.
+  /* Prepend this to any key passed to us.
    * This makes our keys different from all keys used by svn_membuffer_cache_t
    * instances that we don't want to share cached data with.
    */
-  full_key_t prefix;
+  entry_key_t prefix;
 
   /* length of the keys that will be passed to us through the
    * svn_cache_t interface. May be APR_HASH_KEY_STRING.
@@ -2604,6 +2798,15 @@ typedef struct svn_membuffer_cache_t
   svn_mutex__t *mutex;
 } svn_membuffer_cache_t;
 
+/* Return the prefix key used by CACHE. */
+static const char *
+get_prefix_key(const svn_membuffer_cache_t *cache)
+{
+  return (cache->prefix.prefix_idx == NO_INDEX
+       ? cache->combined_key.full_key.data
+       : cache->membuffer->prefix_pool->values[cache->prefix.prefix_idx]);
+}
+
 /* Basically calculate a hash value for KEY of length KEY_LEN, combine it
  * with the CACHE->PREFIX and write the result in CACHE->COMBINED_KEY.
  * This could replace combine_key() entirely but we actually use it only
@@ -2616,7 +2819,7 @@ combine_long_key(svn_membuffer_cache_t *
 {
   apr_uint32_t *digest_buffer;
   char *key_copy;
-  apr_size_t prefix_len = cache->prefix.entry_key.key_len;
+  apr_size_t prefix_len = cache->prefix.key_len;
   apr_size_t aligned_key_len;
 
   /* handle variable-length keys */
@@ -2640,9 +2843,9 @@ combine_long_key(svn_membuffer_cache_t *
 
   /* Combine with prefix. */
   cache->combined_key.entry_key.fingerprint[0]
-    ^= cache->prefix.entry_key.fingerprint[0];
+    ^= cache->prefix.fingerprint[0];
   cache->combined_key.entry_key.fingerprint[1]
-    ^= cache->prefix.entry_key.fingerprint[1];
+    ^= cache->prefix.fingerprint[1];
 }
 
 /* Basically calculate a hash value for KEY of length KEY_LEN, combine it
@@ -2653,47 +2856,55 @@ combine_key(svn_membuffer_cache_t *cache
             const void *key,
             apr_ssize_t key_len)
 {
-  /* short, fixed-size keys are the most common case */
-  if (key_len != APR_HASH_KEY_STRING && key_len <= 16)
-    {
-      const apr_size_t prefix_len = cache->prefix.entry_key.key_len;
+  /* copy of *key, padded with 0 */
+  apr_uint64_t data[2];
 
-      /* Copy of *key, padded with 0.
-       * We put it just behind the prefix already copied into the COMBINED_KEY.
-       * The buffer space has been allocated when the cache was created. */
-      apr_uint64_t *data = (void *)((char *)cache->combined_key.full_key.data + 
-                                    prefix_len);
-      assert(prefix_len <= cache->combined_key.full_key.size - 16);
-      cache->combined_key.entry_key.key_len = prefix_len + 16;
+  /* Do we have to compare full keys? */
+  if (cache->prefix.prefix_idx == NO_INDEX)
+    {
+      combine_long_key(cache, key, key_len);
+      return;
+    }
 
-      data[0] = 0;
+  /* short, fixed-size keys are the most common case */
+  if (key_len == 16)
+    {
+      memcpy(data, key, 16);
+    }
+  else if (key_len == 8)
+    {
+      memcpy(data, key, 8);
       data[1] = 0;
-      memcpy(data, key, key_len);
-
-      /* Scramble key DATA to spread the key space more evenly across the
-       * cache segments and entry buckets.  All of this shall be reversible
-       * to prevent key collisions.  So, we limit ourselves to xor and
-       * permutations.
-       *
-       * As long as we compare the full combined key, the additional
-       * fingerprint collisions introduced by a non-reversible scramble
-       * would simply reduce the cache effectiveness.
-       */
-      data[1] = (data[1] << 27) | (data[1] >> 37);
-      data[1] ^= data[0] & 0xffff;
-      data[0] ^= data[1] & APR_UINT64_C(0xffffffffffff0000);
-
-      /* combine with this cache's namespace */
-      cache->combined_key.entry_key.fingerprint[0]
-        = data[0] ^ cache->prefix.entry_key.fingerprint[0];
-      cache->combined_key.entry_key.fingerprint[1]
-        = data[1] ^ cache->prefix.entry_key.fingerprint[1];
     }
   else
     {
-      /* longer or variably sized keys */
-      combine_long_key(cache, key, key_len);
+      assert(key_len != APR_HASH_KEY_STRING && key_len < 16);
+      data[0] = 0;
+      data[1] = 0;
+      memcpy(data, key, key_len);
     }
+
+  /* Scramble key DATA to spread the key space more evenly across the
+   * cache segments and entry buckets.  All of this shall be reversible
+   * to prevent key collisions.  So, we limit ourselves to xor and
+   * permutations.
+   *
+   * Since the entry key must preserve the full key (prefix and KEY),
+   * the scramble must not introduce KEY collisions.
+   */
+  data[1] = (data[1] << 27) | (data[1] >> 37);
+  data[1] ^= data[0] & 0xffff;
+  data[0] ^= data[1] & APR_UINT64_C(0xffffffffffff0000);
+
+  /* Combine with this cache's prefix.  This is reversible because the
+   * prefix is known through to the respective entry_key element.  So,
+   * knowing entry_key.prefix_id, we can still reconstruct KEY (and the
+   * prefix key).
+   */
+  cache->combined_key.entry_key.fingerprint[0]
+    = data[0] ^ cache->prefix.fingerprint[0];
+  cache->combined_key.entry_key.fingerprint[1]
+    = data[1] ^ cache->prefix.fingerprint[1];
 }
 
 /* Implement svn_cache__vtable_t.get (not thread-safe)
@@ -2940,7 +3151,7 @@ svn_membuffer_cache_get_info(void *cache
 
   /* cache front-end specific data */
 
-  info->id = apr_pstrdup(result_pool, cache->prefix.full_key.data);
+  info->id = apr_pstrdup(result_pool, get_prefix_key(cache));
 
   /* collect info from shared cache back-end */
 
@@ -3129,6 +3340,7 @@ svn_cache__create_membuffer_cache(svn_ca
                                   const char *prefix,
                                   apr_uint32_t priority,
                                   svn_boolean_t thread_safe,
+                                  svn_boolean_t short_lived,
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool)
 {
@@ -3159,28 +3371,50 @@ svn_cache__create_membuffer_cache(svn_ca
   prefix_orig_len = strlen(prefix) + 1;
   prefix_len = ALIGN_VALUE(prefix_orig_len);
 
-  svn_membuf__create(&cache->prefix.full_key, prefix_len, result_pool);
-  memcpy((char *)cache->prefix.full_key.data, prefix, prefix_orig_len);
-  memset((char *)cache->prefix.full_key.data + prefix_orig_len, 0,
-         prefix_len - prefix_orig_len);
-
   /* Construct the folded prefix key. */
   SVN_ERR(svn_checksum(&checksum,
                        svn_checksum_md5,
                        prefix,
                        strlen(prefix),
                        scratch_pool));
-  memcpy(cache->prefix.entry_key.fingerprint, checksum->digest,
-         sizeof(cache->prefix.entry_key.fingerprint));
-  cache->prefix.entry_key.key_len = prefix_len;
-
-  /* Initialize the combined key. Pre-allocate some extra room in the full
-   * key such that we probably don't need to re-alloc. */
-  cache->combined_key.entry_key = cache->prefix.entry_key;
-  svn_membuf__create(&cache->combined_key.full_key, prefix_len + 200,
-                     result_pool);
-  memcpy(cache->combined_key.full_key.data, cache->prefix.full_key.data,
-         prefix_len);
+  memcpy(cache->prefix.fingerprint, checksum->digest,
+         sizeof(cache->prefix.fingerprint));
+  cache->prefix.key_len = prefix_len;
+
+  /* Fix-length keys of up to 16 bytes may be handled without storing the
+   * full key separately for each item. */
+  if (   (klen != APR_HASH_KEY_STRING)
+      && (klen <= sizeof(cache->combined_key.entry_key.fingerprint))
+      && !short_lived)
+    SVN_ERR(prefix_pool_get(&cache->prefix.prefix_idx,
+                            membuffer->prefix_pool,
+                            prefix));
+  else
+    cache->prefix.prefix_idx = NO_INDEX;
+
+  /* If key combining is not guaranteed to produce unique results, we have
+   * to handle full keys.  Otherwise, leave it NULL. */
+  if (cache->prefix.prefix_idx == NO_INDEX)
+    {
+      /* Initialize the combined key. Pre-allocate some extra room in the
+       * full key such that we probably don't need to re-alloc. */
+      cache->combined_key.entry_key = cache->prefix;
+      svn_membuf__create(&cache->combined_key.full_key, prefix_len + 200,
+                         result_pool);
+      memcpy((char *)cache->combined_key.full_key.data, prefix,
+             prefix_orig_len);
+      memset((char *)cache->combined_key.full_key.data + prefix_orig_len, 0,
+             prefix_len - prefix_orig_len);
+    }
+  else
+    {
+      /* Initialize the combined key.  We will never have the full combined
+       * key, so leave it NULL and set its length to 0 to prevent access to
+       * it.  Keep the fingerprint 0 as well b/c it will always be set anew
+       * by combine_key(). */
+      cache->combined_key.entry_key.prefix_idx = cache->prefix.prefix_idx;
+      cache->combined_key.entry_key.key_len = 0;
+    }
 
   /* initialize the generic cache wrapper
    */

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/compress.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/compress.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/compress.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/compress.c Fri Sep 11 15:51:30 2015
@@ -31,6 +31,21 @@
 
 #include "svn_private_config.h"
 
+const char *
+svn_zlib__compiled_version(void)
+{
+  static const char zlib_version_str[] = ZLIB_VERSION;
+
+  return zlib_version_str;
+}
+
+const char *
+svn_zlib__runtime_version(void)
+{
+  return zlibVersion();
+}
+
+
 /* The zlib compressBound function was not exported until 1.2.0. */
 #if ZLIB_VERNUM >= 0x1200
 #define svnCompressBound(LEN) compressBound(LEN)

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/config.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/config.c Fri Sep 11 15:51:30 2015
@@ -55,6 +55,27 @@ struct cfg_section_t
 };
 
 
+/* States that a config option value can assume. */
+typedef enum option_state_t
+{
+  /* Value still needs to be expanded.
+     This is the initial state for *all* values. */
+  option_state_needs_expanding,
+
+  /* Value is currently being expanded.
+     This transitional state allows for detecting cyclic dependencies. */
+  option_state_expanding,
+
+  /* Expanded value is available.
+     Values that never needed expanding directly go into that state
+     skipping option_state_expanding. */
+  option_state_expanded,
+
+  /* The value expansion is cyclic which results in "undefined" behavior.
+     This is to return a defined value ("") in that case. */
+  option_state_cyclic
+} option_state_t;
+
 /* Option table entries. */
 typedef struct cfg_option_t cfg_option_t;
 struct cfg_option_t
@@ -71,10 +92,10 @@ struct cfg_option_t
   /* The expanded option value. */
   const char *x_value;
 
-  /* Expansion flag. If this is TRUE, this value has already been expanded.
-     In this case, if x_value is NULL, no expansions were necessary,
-     and value should be used directly. */
-  svn_boolean_t expanded;
+  /* Expansion state. If this is option_state_expanded, VALUE has already
+     been expanded.  In this case, if x_value is NULL, no expansions were
+     necessary, and value should be used directly. */
+  option_state_t state;
 };
 
 
@@ -396,12 +417,13 @@ svn_config_merge(svn_config_t *cfg, cons
 static svn_boolean_t
 rmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option)
 {
-  /* Only clear the `expanded' flag if the value actually contains
+  /* Only reset the expansion state if the value actually contains
      variable expansions. */
-  if (option->expanded && option->x_value != NULL)
+  if (   (option->state == option_state_expanded && option->x_value != NULL)
+      || option->state == option_state_cyclic)
     {
       option->x_value = NULL;
-      option->expanded = FALSE;
+      option->state = option_state_needs_expanding;
     }
 
   return FALSE;
@@ -482,7 +504,7 @@ find_option(svn_config_t *cfg, const cha
 
 
 /* Has a bi-directional dependency with make_string_from_option(). */
-static void
+static svn_boolean_t
 expand_option_value(svn_config_t *cfg, cfg_section_t *section,
                     const char *opt_value, const char **opt_x_valuep,
                     apr_pool_t *x_pool);
@@ -496,7 +518,20 @@ make_string_from_option(const char **val
                         apr_pool_t* x_pool)
 {
   /* Expand the option value if necessary. */
-  if (!opt->expanded)
+  if (   opt->state == option_state_expanding
+      || opt->state == option_state_cyclic)
+    {
+      /* Recursion is not supported.  Since we can't produce an error
+       * nor should we abort the process, the next best thing is to
+       * report the recursive part as an empty string. */
+      *valuep = "";
+
+      /* Go into "value undefined" state. */
+      opt->state = option_state_cyclic;
+
+      return;
+    }
+  else if (opt->state == option_state_needs_expanding)
     {
       /* before attempting to expand an option, check for the placeholder.
        * If none is there, there is no point in calling expand_option_value.
@@ -511,9 +546,16 @@ make_string_from_option(const char **val
 
           tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
 
-          expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
-          opt->expanded = TRUE;
+          /* Expand the value. During that process, have the option marked
+           * as "expanding" to detect cycles. */
+          opt->state = option_state_expanding;
+          if (expand_option_value(cfg, section, opt->value, &opt->x_value,
+                                  tmp_pool))
+            opt->state = option_state_expanded;
+          else
+            opt->state = option_state_cyclic;
 
+          /* Ensure the expanded value is allocated in a permanent pool. */
           if (x_pool != cfg->x_pool)
             {
               /* Grab the fully expanded value from tmp_pool before its
@@ -527,7 +569,7 @@ make_string_from_option(const char **val
         }
       else
         {
-          opt->expanded = TRUE;
+          opt->state = option_state_expanded;
         }
     }
 
@@ -549,8 +591,9 @@ make_string_from_option(const char **val
 
 /* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP.
    If no variable replacements are done, set *OPT_X_VALUEP to
-   NULL. Allocate from X_POOL. */
-static void
+   NULL.  Return TRUE if the expanded value is defined and FALSE
+   for recursive definitions.  Allocate from X_POOL. */
+static svn_boolean_t
 expand_option_value(svn_config_t *cfg, cfg_section_t *section,
                     const char *opt_value, const char **opt_x_valuep,
                     apr_pool_t *x_pool)
@@ -587,6 +630,18 @@ expand_option_value(svn_config_t *cfg, c
                  should terminate. */
               make_string_from_option(&cstring, cfg, section, x_opt, x_pool);
 
+              /* Values depending on cyclic values must also be marked as
+               * "undefined" because they might themselves form cycles with
+               * the one cycle we just detected.  Due to the early abort of
+               * the recursion, we won't follow and thus detect dependent
+               * cycles anymore.
+               */
+              if (x_opt->state == option_state_cyclic)
+                {
+                  *opt_x_valuep = "";
+                  return FALSE;
+                }
+
               /* Append the plain text preceding the expansion. */
               len = name_start - FMT_START_LEN - copy_from;
               if (buf == NULL)
@@ -625,6 +680,9 @@ expand_option_value(svn_config_t *cfg, c
     }
   else
     *opt_x_valuep = NULL;
+
+  /* Expansion has a well-defined answer. */
+  return TRUE;
 }
 
 static cfg_section_t *
@@ -664,7 +722,7 @@ svn_config_create_option(cfg_option_t **
 
   o->value = apr_pstrdup(pool, value);
   o->x_value = NULL;
-  o->expanded = FALSE;
+  o->state = option_state_needs_expanding;
 
   *opt = o;
 }
@@ -685,7 +743,8 @@ svn_config__is_expanded(svn_config_t *cf
     return FALSE;
 
   /* already expanded? */
-  if (opt->expanded)
+  if (   opt->state == option_state_expanded
+      || opt->state == option_state_cyclic)
     return TRUE;
 
   /* needs expansion? */
@@ -719,8 +778,14 @@ svn_config_get(svn_config_t *cfg, const
           {
             apr_pool_t *tmp_pool = svn_pool_create(cfg->pool);
             const char *x_default;
-            expand_option_value(cfg, sec, default_value, &x_default, tmp_pool);
-            if (x_default)
+            if (!expand_option_value(cfg, sec, default_value, &x_default,
+                                     tmp_pool))
+              {
+                /* Recursive definitions are not supported.
+                   Normalize the answer in that case. */
+                *valuep = "";
+              }
+            else if (x_default)
               {
                 svn_stringbuf_set(cfg->tmp_value, x_default);
                 *valuep = cfg->tmp_value->data;
@@ -758,7 +823,7 @@ svn_config_set(svn_config_t *cfg,
     {
       /* Replace the option's value. */
       opt->value = apr_pstrdup(cfg->pool, value);
-      opt->expanded = FALSE;
+      opt->state = option_state_needs_expanding;
       return;
     }
 
@@ -1171,7 +1236,7 @@ svn_config_dup(svn_config_t **cfgp,
 
       destopt->value = apr_pstrdup(pool, srcopt->value);
       destopt->x_value = apr_pstrdup(pool, srcopt->x_value);
-      destopt->expanded = srcopt->expanded;
+      destopt->state = srcopt->state;
       apr_hash_set(destsec->options,
                    apr_pstrdup(pool, (const char*)optkey),
                    optkeyLength, destopt);

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_auth.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_auth.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_auth.c Fri Sep 11 15:51:30 2015
@@ -144,7 +144,7 @@ svn_config_write_auth_data(apr_hash_t *h
             apr_psprintf(pool, _("Error writing hash to '%s'"),
                          svn_dirent_local_style(auth_path, pool)));
   SVN_ERR(svn_stream_close(stream));
-  SVN_ERR(svn_io_file_rename(tmp_path, auth_path, pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, auth_path, FALSE, pool));
 
   /* To be nice, remove the realmstring from the hash again, just in
      case the caller wants their hash unchanged.

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_file.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/config_file.c Fri Sep 11 15:51:30 2015
@@ -1407,7 +1407,7 @@ svn_config_get_user_config_path(const ch
     if (! homedir)
       return SVN_NO_ERROR;
     *path = svn_dirent_join_many(pool,
-                               svn_dirent_canonicalize(homedir, pool),
+                                 homedir,
                                SVN_CONFIG__USR_DIRECTORY, fname, SVN_VA_NULL);
   }
 #endif /* WIN32 */

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/deprecated.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/deprecated.c Fri Sep 11 15:51:30 2015
@@ -889,6 +889,14 @@ svn_io_stat_dirent(const svn_io_dirent2_
                                 scratch_pool));
 }
 
+svn_error_t *
+svn_io_file_rename(const char *from_path, const char *to_path,
+                   apr_pool_t *pool)
+{
+  return svn_error_trace(svn_io_file_rename2(from_path, to_path,
+                                             FALSE, pool));
+}
+
 /*** From constructors.c ***/
 svn_log_changed_path_t *
 svn_log_changed_path_dup(const svn_log_changed_path_t *changed_path,
@@ -1501,7 +1509,11 @@ void
 svn_auth_get_gpg_agent_simple_provider(svn_auth_provider_object_t **provider,
                                        apr_pool_t *pool)
 {
+#ifdef SVN_HAVE_GPG_AGENT
   svn_auth__get_gpg_agent_simple_provider(provider, pool);
+#else
+  svn_auth__get_dummmy_simple_provider(provider, pool);
+#endif /* SVN_HAVE_GPG_AGENT */
 }
 #endif /* !WIN32 */
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/dirent_uri.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/dirent_uri.c Fri Sep 11 15:51:30 2015
@@ -495,14 +495,20 @@ canonicalize(path_type_t type, const cha
 #ifdef SVN_USE_DOS_PATHS
       /* If this is the first path segment of a file:// URI and it contains a
          windows drive letter, convert the drive letter to upper case. */
-      else if (url && canon_segments == 1 && seglen == 2 &&
+      else if (url && canon_segments == 1 && seglen >= 2 &&
                (strncmp(canon, "file:", 5) == 0) &&
                src[0] >= 'a' && src[0] <= 'z' && src[1] == ':')
         {
           *(dst++) = canonicalize_to_upper(src[0]);
           *(dst++) = ':';
-          if (*next)
-            *(dst++) = *next;
+          if (seglen > 2) /* drive relative path */
+            {
+              memcpy(dst, src + 2, seglen - 2);
+              dst += seglen - 2;
+            }
+
+          if (slash_len)
+            *(dst++) = '/';
           canon_segments++;
         }
 #endif /* SVN_USE_DOS_PATHS */
@@ -2398,8 +2404,11 @@ svn_uri_get_dirent_from_file_url(const c
         if (dup_path[1] == '|')
           dup_path[1] = ':';
 
-        if (dup_path[2] == '/' || dup_path[2] == '\0')
+        if (dup_path[2] == '/' || dup_path[2] == '\\' || dup_path[2] == '\0')
           {
+            /* Dirents have upper case drive letters in their canonical form */
+            dup_path[0] = canonicalize_to_upper(dup_path[0]);
+
             if (dup_path[2] == '\0')
               {
                 /* A valid dirent for the driveroot must be like "C:/" instead of
@@ -2412,6 +2421,8 @@ svn_uri_get_dirent_from_file_url(const c
                 new_path[3] = '\0';
                 dup_path = new_path;
               }
+            else
+              dup_path[2] = '/'; /* Ensure not relative for '\' after drive! */
           }
       }
     if (hostname)

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/io.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/io.c Fri Sep 11 15:51:30 2015
@@ -142,6 +142,23 @@
 #endif
 
 #ifdef WIN32
+
+#if _WIN32_WINNT < 0x600 /* Does the SDK assume Windows Vista+? */
+typedef struct _FILE_RENAME_INFO {
+  BOOL   ReplaceIfExists;
+  HANDLE RootDirectory;
+  DWORD  FileNameLength;
+  WCHAR  FileName[1];
+} FILE_RENAME_INFO, *PFILE_RENAME_INFO;
+
+typedef struct _FILE_DISPOSITION_INFO {
+  BOOL DeleteFile;
+} FILE_DISPOSITION_INFO, *PFILE_DISPOSITION_INFO;
+
+#define FileRenameInfo 3
+#define FileDispositionInfo 4
+#endif /* WIN32 < Vista */
+
 /* One-time initialization of the late bound Windows API functions. */
 static volatile svn_atomic_t win_dynamic_imports_state = 0;
 
@@ -152,7 +169,13 @@ typedef DWORD (WINAPI *GETFINALPATHNAMEB
                DWORD cchFilePath,
                DWORD dwFlags);
 
+typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile,
+                                                    int FileInformationClass,
+                                                    LPVOID lpFileInformation,
+                                                    DWORD dwBufferSize);
+
 static GETFINALPATHNAMEBYHANDLE get_final_path_name_by_handle_proc = NULL;
+static SetFileInformationByHandle_t set_file_information_by_handle_proc = NULL;
 
 /* Forward declaration. */
 static svn_error_t * io_win_read_link(svn_string_t **dest,
@@ -555,10 +578,8 @@ svn_io_open_uniquely_named(apr_file_t **
                 continue;
 
 #ifdef WIN32
-              apr_err_2 = APR_TO_OS_ERROR(apr_err);
-
-              if (apr_err_2 == ERROR_ACCESS_DENIED ||
-                  apr_err_2 == ERROR_SHARING_VIOLATION)
+              if (apr_err == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED) ||
+                  apr_err == APR_FROM_OS_ERROR(ERROR_SHARING_VIOLATION))
                 {
                   /* The file is in use by another process or is hidden;
                      create a new name, but don't do this 99999 times in
@@ -750,7 +771,7 @@ svn_io_copy_link(const char *src,
                                     ".tmp", pool));
 
   /* Move the tmp-link to link. */
-  return svn_io_file_rename(dst_tmp, dst, pool);
+  return svn_io_file_rename2(dst_tmp, dst, FALSE, pool);
 
 #else
   return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
@@ -919,7 +940,7 @@ svn_io_copy_file(const char *src,
   if (copy_perms)
     SVN_ERR(svn_io_copy_perms(src, dst_tmp, pool));
 
-  return svn_error_trace(svn_io_file_rename(dst_tmp, dst, pool));
+  return svn_error_trace(svn_io_file_rename2(dst_tmp, dst, FALSE, pool));
 }
 
 #if !defined(WIN32) && !defined(__OS2__)
@@ -1504,7 +1525,7 @@ reown_file(const char *path,
   SVN_ERR(svn_io_open_unique_file3(NULL, &unique_name,
                                    svn_dirent_dirname(path, pool),
                                    svn_io_file_del_none, pool, pool));
-  SVN_ERR(svn_io_file_rename(path, unique_name, pool));
+  SVN_ERR(svn_io_file_rename2(path, unique_name, FALSE, pool));
   SVN_ERR(svn_io_copy_file(unique_name, path, TRUE, pool));
   return svn_error_trace(svn_io_remove_file2(unique_name, FALSE, pool));
 }
@@ -1861,11 +1882,18 @@ io_win_file_attrs_set(const char *fname,
 
 static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
 {
-    get_final_path_name_by_handle_proc = (GETFINALPATHNAMEBYHANDLE)
-      GetProcAddress(GetModuleHandleA("kernel32.dll"),
-                     "GetFinalPathNameByHandleW");
+  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
 
-    return SVN_NO_ERROR;
+  if (kernel32)
+    {
+      get_final_path_name_by_handle_proc = (GETFINALPATHNAMEBYHANDLE)
+        GetProcAddress(kernel32, "GetFinalPathNameByHandleW");
+
+      set_file_information_by_handle_proc = (SetFileInformationByHandle_t)
+        GetProcAddress(kernel32, "SetFileInformationByHandle");
+    }
+
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t * io_win_read_link(svn_string_t **dest,
@@ -1937,6 +1965,130 @@ static svn_error_t * io_win_read_link(sv
       }
 }
 
+/* Wrapper around Windows API function SetFileInformationByHandle() that
+ * returns APR status instead of boolean flag. */
+static apr_status_t
+win32_set_file_information_by_handle(HANDLE hFile,
+                                     int FileInformationClass,
+                                     LPVOID lpFileInformation,
+                                     DWORD dwBufferSize)
+{
+  svn_error_clear(svn_atomic__init_once(&win_dynamic_imports_state,
+                                        win_init_dynamic_imports,
+                                        NULL, NULL));
+
+  if (!set_file_information_by_handle_proc)
+    {
+      return SVN_ERR_UNSUPPORTED_FEATURE;
+    }
+
+  if (!set_file_information_by_handle_proc(hFile, FileInformationClass,
+                                           lpFileInformation,
+                                           dwBufferSize))
+    {
+      return apr_get_os_error();
+    }
+
+  return APR_SUCCESS;
+}
+
+svn_error_t *
+svn_io__win_delete_file_on_close(apr_file_t *file,
+                                 const char *path,
+                                 apr_pool_t *pool)
+{
+  FILE_DISPOSITION_INFO disposition_info;
+  HANDLE hFile;
+  apr_status_t status;
+
+  apr_os_file_get(&hFile, file);
+
+  disposition_info.DeleteFile = TRUE;
+
+  status = win32_set_file_information_by_handle(hFile, FileDispositionInfo,
+                                                &disposition_info,
+                                                sizeof(disposition_info));
+
+  if (status)
+    {
+      return svn_error_wrap_apr(status, _("Can't remove file '%s'"),
+                                svn_dirent_local_style(path, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io__win_rename_open_file(apr_file_t *file,
+                             const char *from_path,
+                             const char *to_path,
+                             apr_pool_t *pool)
+{
+  WCHAR *w_final_abspath;
+  size_t path_len;
+  size_t rename_size;
+  FILE_RENAME_INFO *rename_info;
+  HANDLE hFile;
+  apr_status_t status;
+
+  apr_os_file_get(&hFile, file);
+
+  SVN_ERR(svn_io__utf8_to_unicode_longpath(
+            &w_final_abspath, svn_dirent_local_style(to_path,pool),
+            pool));
+
+  path_len = wcslen(w_final_abspath);
+  rename_size = sizeof(*rename_info) + sizeof(WCHAR) * path_len;
+
+  /* The rename info struct doesn't need hacks for long paths,
+     so no ugly escaping calls here */
+  rename_info = apr_pcalloc(pool, rename_size);
+  rename_info->ReplaceIfExists = TRUE;
+  rename_info->FileNameLength = path_len;
+  memcpy(rename_info->FileName, w_final_abspath, path_len * sizeof(WCHAR));
+
+  status = win32_set_file_information_by_handle(hFile, FileRenameInfo,
+                                                rename_info,
+                                                rename_size);
+
+  if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status))
+    {
+      /* Set the destination file writable because Windows will not allow
+         us to rename when final_abspath is read-only. */
+      SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool));
+
+      status = win32_set_file_information_by_handle(hFile,
+                                                    FileRenameInfo,
+                                                    rename_info,
+                                                    rename_size);
+   }
+
+  /* Windows returns Vista+ client accessing network share stored on Windows
+     Server 2003 returns ERROR_ACCESS_DENIED. The same happens when Vista+
+     client access Windows Server 2008 with disabled SMBv2 protocol.
+
+     So return SVN_ERR_UNSUPPORTED_FEATURE in this case like we do when
+     SetFileInformationByHandle() is not available and let caller to
+     handle it.
+
+     See "Access denied error on checkout-commit after updating to 1.9.X"
+     discussion on dev@s.a.o:
+     http://svn.haxx.se/dev/archive-2015-09/0054.shtml */
+  if (status == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED))
+    {
+      status = SVN_ERR_UNSUPPORTED_FEATURE;
+    }
+
+  if (status)
+    {
+      return svn_error_wrap_apr(status, _("Can't move '%s' to '%s'"),
+                                svn_dirent_local_style(from_path, pool),
+                                svn_dirent_local_style(to_path, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 #endif /* WIN32 */
 
 svn_error_t *
@@ -2120,7 +2272,6 @@ svn_io_is_file_executable(svn_boolean_t
 
 
 /*** File locking. ***/
-#if !defined(WIN32) && !defined(__OS2__)
 /* Clear all outstanding locks on ARG, an open apr_file_t *. */
 static apr_status_t
 file_clear_locks(void *arg)
@@ -2135,7 +2286,6 @@ file_clear_locks(void *arg)
 
   return 0;
 }
-#endif
 
 svn_error_t *
 svn_io_lock_open_file(apr_file_t *lockfile_handle,
@@ -2193,13 +2343,14 @@ svn_io_lock_open_file(apr_file_t *lockfi
         }
     }
 
-/* On Windows and OS/2 file locks are automatically released when
-   the file handle closes */
-#if !defined(WIN32) && !defined(__OS2__)
+  /* On Windows, a process may not release file locks before closing the
+     handle, and in this case the outstanding locks are unlocked by the OS.
+     However, this is not recommended, because the actual unlocking may be
+     postponed depending on available system resources.  We explicitly unlock
+     the file as a part of the pool cleanup handler. */
   apr_pool_cleanup_register(pool, lockfile_handle,
                             file_clear_locks,
                             apr_pool_cleanup_null);
-#endif
 
   return SVN_NO_ERROR;
 }
@@ -2223,11 +2374,7 @@ svn_io_unlock_open_file(apr_file_t *lock
     return svn_error_wrap_apr(apr_err, _("Can't unlock file '%s'"),
                               try_utf8_from_internal_style(fname, pool));
 
-/* On Windows and OS/2 file locks are automatically released when
-   the file handle closes */
-#if !defined(WIN32) && !defined(__OS2__)
   apr_pool_cleanup_kill(pool, lockfile_handle, file_clear_locks);
-#endif
 
   return SVN_NO_ERROR;
 }
@@ -2301,6 +2448,14 @@ svn_error_t *svn_io_file_flush_to_disk(a
                                        apr_pool_t *pool)
 {
   apr_os_file_t filehand;
+  const char *fname;
+  apr_status_t apr_err;
+
+  /* We need this only in case of an error but this is cheap to get -
+   * so we do it here for clarity. */
+  apr_err = apr_file_name_get(&fname, file);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err, _("Can't get file name"));
 
   /* ### In apr 1.4+ we could delegate most of this function to
          apr_file_sync(). The only major difference is that this doesn't
@@ -2318,7 +2473,8 @@ svn_error_t *svn_io_file_flush_to_disk(a
 
     if (! FlushFileBuffers(filehand))
         return svn_error_wrap_apr(apr_get_os_error(),
-                                  _("Can't flush file to disk"));
+                                  _("Can't flush file '%s' to disk"),
+                                  try_utf8_from_internal_style(fname, pool));
 
 #else
       int rv;
@@ -2339,7 +2495,8 @@ svn_error_t *svn_io_file_flush_to_disk(a
 
       if (rv == -1)
         return svn_error_wrap_apr(apr_get_os_error(),
-                                  _("Can't flush file to disk"));
+                                  _("Can't flush file '%s' to disk"),
+                                  try_utf8_from_internal_style(fname, pool));
 
 #endif
   }
@@ -3864,7 +4021,7 @@ svn_io_write_atomic(const char *final_pa
     err = svn_io_copy_perms(copy_perms_path, tmp_path, scratch_pool);
 
   if (!err)
-    err = svn_io_file_rename(tmp_path, final_path, scratch_pool);
+    err = svn_io_file_rename2(tmp_path, final_path, TRUE, scratch_pool);
 
   if (err)
     {
@@ -3878,21 +4035,6 @@ svn_io_write_atomic(const char *final_pa
                                                       scratch_pool));
     }
 
-#if SVN_ON_POSIX
-  {
-    /* On POSIX, the file name is stored in the file's directory entry.
-       Hence, we need to fsync() that directory as well.
-       On other operating systems, we'd only be asking for trouble
-       by trying to open and fsync a directory. */
-    apr_file_t *file;
-
-    SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
-                             scratch_pool));
-    SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
-    SVN_ERR(svn_io_file_close(file, scratch_pool));
-  }
-#endif
-
   return SVN_NO_ERROR;
 }
 
@@ -4014,20 +4156,53 @@ svn_io_stat(apr_finfo_t *finfo, const ch
   return SVN_NO_ERROR;
 }
 
+#if defined(WIN32)
+/* Platform specific implementation of apr_file_rename() to workaround
+   APR problems on Windows. */
+static apr_status_t
+win32_file_rename(const WCHAR *from_path_w,
+                  const WCHAR *to_path_w,
+                  svn_boolean_t flush_to_disk)
+{
+  /* APR calls MoveFileExW() with MOVEFILE_COPY_ALLOWED, while we rely
+   * that rename is atomic operation. Call MoveFileEx directly on Windows
+   * without MOVEFILE_COPY_ALLOWED flag to workaround it.
+   */
+
+  DWORD flags = MOVEFILE_REPLACE_EXISTING;
+
+  if (flush_to_disk)
+    {
+      /* Do not return until the file has actually been moved on the disk. */
+      flags |= MOVEFILE_WRITE_THROUGH;
+    }
+
+  if (!MoveFileExW(from_path_w, to_path_w, flags))
+      return apr_get_os_error();
+
+  return APR_SUCCESS;
+}
+#endif
 
 svn_error_t *
-svn_io_file_rename(const char *from_path, const char *to_path,
-                   apr_pool_t *pool)
+svn_io_file_rename2(const char *from_path, const char *to_path,
+                    svn_boolean_t flush_to_disk, apr_pool_t *pool)
 {
   apr_status_t status = APR_SUCCESS;
   const char *from_path_apr, *to_path_apr;
+#if defined(WIN32)
+  WCHAR *from_path_w;
+  WCHAR *to_path_w;
+#endif
 
   SVN_ERR(cstring_from_utf8(&from_path_apr, from_path, pool));
   SVN_ERR(cstring_from_utf8(&to_path_apr, to_path, pool));
 
-  status = apr_file_rename(from_path_apr, to_path_apr, pool);
+#if defined(WIN32)
+  SVN_ERR(svn_io__utf8_to_unicode_longpath(&from_path_w, from_path_apr, pool));
+  SVN_ERR(svn_io__utf8_to_unicode_longpath(&to_path_w, to_path_apr, pool));
+  status = win32_file_rename(from_path_w, to_path_w, flush_to_disk);
 
-#if defined(WIN32) || defined(__OS2__)
   /* If the target file is read only NTFS reports EACCESS and
      FAT/FAT32 reports EEXIST */
   if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status))
@@ -4037,9 +4212,25 @@ svn_io_file_rename(const char *from_path
          allow renaming when from_path is read only. */
       SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool));
 
+      status = win32_file_rename(from_path_w, to_path_w, flush_to_disk);
+    }
+  WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w,
+                                             flush_to_disk));
+#elif defined(__OS2__)
+  status = apr_file_rename(from_path_apr, to_path_apr, pool);
+  /* If the target file is read only NTFS reports EACCESS and
+     FAT/FAT32 reports EEXIST */
+  if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status))
+    {
+      /* Set the destination file writable because OS/2 will not
+         allow us to rename when to_path is read-only, but will
+         allow renaming when from_path is read only. */
+      SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool));
+
       status = apr_file_rename(from_path_apr, to_path_apr, pool);
     }
-  WIN32_RETRY_LOOP(status, apr_file_rename(from_path_apr, to_path_apr, pool));
+#else
+  status = apr_file_rename(from_path_apr, to_path_apr, pool);
 #endif /* WIN32 || __OS2__ */
 
   if (status)
@@ -4047,6 +4238,34 @@ svn_io_file_rename(const char *from_path
                               svn_dirent_local_style(from_path, pool),
                               svn_dirent_local_style(to_path, pool));
 
+#if defined(SVN_ON_POSIX)
+  if (flush_to_disk)
+    {
+      /* On POSIX, the file name is stored in the file's directory entry.
+         Hence, we need to fsync() that directory as well.
+         On other operating systems, we'd only be asking for trouble
+         by trying to open and fsync a directory. */
+      const char *dirname;
+      apr_file_t *file;
+
+      dirname = svn_dirent_dirname(to_path, pool);
+      SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+                               pool));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+    }
+#elif !defined(WIN32)
+  /* Flush the target of the rename to disk. */
+  if (flush_to_disk)
+    {
+      apr_file_t *file;
+      SVN_ERR(svn_io_file_open(&file, to_path, APR_WRITE,
+                               APR_OS_DEFAULT, pool));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+    }
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -4055,8 +4274,8 @@ svn_error_t *
 svn_io_file_move(const char *from_path, const char *to_path,
                  apr_pool_t *pool)
 {
-  svn_error_t *err = svn_error_trace(svn_io_file_rename(from_path, to_path,
-                                                        pool));
+  svn_error_t *err = svn_error_trace(svn_io_file_rename2(from_path, to_path,
+                                                         FALSE, pool));
 
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
@@ -4216,8 +4435,8 @@ svn_io_dir_remove_nonrecursive(const cha
   {
     svn_boolean_t retry = TRUE;
 
-    if (APR_TO_OS_ERROR(status) == ERROR_DIR_NOT_EMPTY)
-      {
+    if (status == APR_FROM_OS_ERROR(ERROR_DIR_NOT_EMPTY))
+    {
         apr_status_t empty_status = dir_is_empty(dirname_apr, pool);
 
         if (APR_STATUS_IS_ENOTEMPTY(empty_status))
@@ -4496,7 +4715,7 @@ svn_io_write_version_file(const char *pa
 #endif /* WIN32 || __OS2__ */
 
   /* rename the temp file as the real destination */
-  SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
+  SVN_ERR(svn_io_file_rename2(path_tmp, path, FALSE, pool));
 
   /* And finally remove the perms to make it read only */
   return svn_io_set_file_read_only(path, FALSE, pool);
@@ -4924,10 +5143,8 @@ temp_file_create(apr_file_t **new_file,
               if (!apr_err_2 && finfo.filetype == APR_DIR)
                 continue;
 
-              apr_err_2 = APR_TO_OS_ERROR(apr_err);
-
-              if (apr_err_2 == ERROR_ACCESS_DENIED ||
-                  apr_err_2 == ERROR_SHARING_VIOLATION)
+              if (apr_err == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED) ||
+                  apr_err == APR_FROM_OS_ERROR(ERROR_SHARING_VIOLATION))
                 {
                   /* The file is in use by another process or is hidden;
                      create a new name, but don't do this 99999 times in

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/mergeinfo.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/mergeinfo.c Fri Sep 11 15:51:30 2015
@@ -2359,7 +2359,7 @@ svn_mergeinfo__catalog_to_formatted_stri
           svn_stringbuf_appendcstr(output_buf, "\n");
         }
     }
-#if SVN_DEBUG
+#ifdef SVN_DEBUG
   else if (!catalog)
     {
       output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool);

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_subr/mutex.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_subr/mutex.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_subr/mutex.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_subr/mutex.c Fri Sep 11 15:51:30 2015
@@ -105,3 +105,13 @@ svn_mutex__unlock(svn_mutex__t *mutex,
 
   return err;
 }
+
+#if APR_HAS_THREADS
+
+apr_thread_mutex_t *
+svn_mutex__get(svn_mutex__t *mutex)
+{
+  return mutex->mutex;
+}
+
+#endif