You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2015/08/19 04:35:15 UTC

svn commit: r1696514 [9/10] - in /subversion/branches/patch-exec: ./ build/ac-macros/ notes/ subversion/bindings/javahl/native/ subversion/bindings/swig/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs_fs/...

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/cache-membuffer.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/cache-membuffer.c Wed Aug 19 02:35:12 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,182 @@ 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)
+    {
+      *prefix_idx = value - prefix_pool->values;
+      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 +433,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 +449,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 +519,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 +694,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 +981,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 +1365,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 +1428,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 +1528,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 +1856,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 +1866,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 +1982,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" */
@@ -2581,11 +2773,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 +2796,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 +2817,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 +2841,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 +2854,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 +3149,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 +3338,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 +3369,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/patch-exec/subversion/libsvn_subr/compress.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/compress.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/compress.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/compress.c Wed Aug 19 02:35:12 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/patch-exec/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/deprecated.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/deprecated.c Wed Aug 19 02:35:12 2015
@@ -1497,12 +1497,14 @@ svn_auth_get_keychain_ssl_client_cert_pw
 #endif /* DARWIN */
 
 #if !defined(WIN32)
+#ifdef SVN_HAVE_GPG_AGENT
 void
 svn_auth_get_gpg_agent_simple_provider(svn_auth_provider_object_t **provider,
                                        apr_pool_t *pool)
 {
   svn_auth__get_gpg_agent_simple_provider(provider, pool);
 }
+#endif /* SVN_HAVE_GPG_AGENT */
 #endif /* !WIN32 */
 
 svn_error_t *

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/io.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/io.c Wed Aug 19 02:35:12 2015
@@ -3888,7 +3888,7 @@ svn_io_write_atomic(const char *final_pa
                                                       scratch_pool));
     }
 
-#if SVN_ON_POSIX
+#ifdef 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.

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/mergeinfo.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/mergeinfo.c Wed Aug 19 02:35:12 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/patch-exec/subversion/libsvn_subr/mutex.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/mutex.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/mutex.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/mutex.c Wed Aug 19 02:35:12 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

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/stream.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/stream.c Wed Aug 19 02:35:12 2015
@@ -197,8 +197,12 @@ svn_error_t *
 svn_stream_skip(svn_stream_t *stream, apr_size_t len)
 {
   if (stream->skip_fn == NULL)
-    return svn_error_trace(
-            skip_default_handler(stream->baton, len, stream->read_full_fn));
+    {
+      svn_read_fn_t read_fn = stream->read_full_fn ? stream->read_full_fn
+                                                   : stream->read_fn;
+      return svn_error_trace(skip_default_handler(stream->baton, len,
+                                                  read_fn));
+    }
 
   return svn_error_trace(stream->skip_fn(stream->baton, len));
 }
@@ -938,8 +942,9 @@ static svn_error_t *
 data_available_handler_apr(void *baton, svn_boolean_t *data_available)
 {
   struct baton_apr *btn = baton;
-  apr_pollfd_t pfd;
   apr_status_t status;
+#if !defined(WIN32) || APR_FILES_AS_SOCKETS
+  apr_pollfd_t pfd;
   int n;
 
   pfd.desc_type = APR_POLL_FILE;
@@ -969,6 +974,24 @@ data_available_handler_apr(void *baton,
                                     "failed")),
                               NULL);
     }
+#else
+  HANDLE h;
+  DWORD dwAvail;
+  status = apr_os_file_get(&h, btn->file);
+
+  if (status)
+    return svn_error_wrap_apr(status, NULL);
+
+  if (PeekNamedPipe(h, NULL, 0, NULL, &dwAvail, NULL))
+    {
+      *data_available = (dwAvail > 0);
+      return SVN_NO_ERROR;
+    }
+
+  return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED,
+                          svn_error_wrap_apr(apr_get_os_error(), NULL),
+                          _("Windows doesn't support polling on files"));
+#endif
 }
 
 static svn_boolean_t

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/sysinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/sysinfo.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/sysinfo.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/sysinfo.c Wed Aug 19 02:35:12 2015
@@ -45,6 +45,7 @@
 #include "svn_version.h"
 
 #include "private/svn_sqlite.h"
+#include "private/svn_subr_private.h"
 
 #include "sysinfo.h"
 #include "svn_private_config.h"
@@ -125,7 +126,7 @@ const apr_array_header_t *
 svn_sysinfo__linked_libs(apr_pool_t *pool)
 {
   svn_version_ext_linked_lib_t *lib;
-  apr_array_header_t *array = apr_array_make(pool, 3, sizeof(*lib));
+  apr_array_header_t *array = apr_array_make(pool, 5, sizeof(*lib));
 
   lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
   lib->name = "APR";
@@ -142,6 +143,11 @@ svn_sysinfo__linked_libs(apr_pool_t *poo
 #endif
 
   lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
+  lib->name = "Expat";
+  lib->compiled_version = apr_pstrdup(pool, svn_xml__compiled_version());
+  lib->runtime_version = apr_pstrdup(pool, svn_xml__runtime_version());
+
+  lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
   lib->name = "SQLite";
   lib->compiled_version = apr_pstrdup(pool, svn_sqlite__compiled_version());
 #ifdef SVN_SQLITE_INLINE
@@ -150,6 +156,11 @@ svn_sysinfo__linked_libs(apr_pool_t *poo
   lib->runtime_version = apr_pstrdup(pool, svn_sqlite__runtime_version());
 #endif
 
+  lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
+  lib->name = "ZLib";
+  lib->compiled_version = apr_pstrdup(pool, svn_zlib__compiled_version());
+  lib->runtime_version = apr_pstrdup(pool, svn_zlib__runtime_version());
+
   return array;
 }
 

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/temp_serializer.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/temp_serializer.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/temp_serializer.c Wed Aug 19 02:35:12 2015
@@ -366,7 +366,7 @@ svn_temp_serializer__get(svn_temp_serial
  * proper pointer value.
  */
 void
-svn_temp_deserializer__resolve(void *buffer, void **ptr)
+svn_temp_deserializer__resolve(const void *buffer, void **ptr)
 {
   /* All pointers are stored as offsets to the buffer start
    * (of the respective serialized sub-struct). */

Modified: subversion/branches/patch-exec/subversion/libsvn_subr/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_subr/xml.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_subr/xml.c (original)
+++ subversion/branches/patch-exec/subversion/libsvn_subr/xml.c Wed Aug 19 02:35:12 2015
@@ -45,6 +45,28 @@
 #error Expat is unusable -- it has been compiled for wide characters
 #endif
 
+const char *
+svn_xml__compiled_version(void)
+{
+  static const char xml_version_str[] = APR_STRINGIFY(XML_MAJOR_VERSION)
+                                        "." APR_STRINGIFY(XML_MINOR_VERSION)
+                                        "." APR_STRINGIFY(XML_MICRO_VERSION);
+
+  return xml_version_str;
+}
+
+const char *
+svn_xml__runtime_version(void)
+{
+  const char *expat_version = XML_ExpatVersion();
+
+  if (!strncmp(expat_version, "expat_", 6))
+    expat_version += 6;
+
+  return expat_version;
+}
+
+
 /* The private internals for a parser object. */
 struct svn_xml_parser_t
 {

Modified: subversion/branches/patch-exec/subversion/mod_authz_svn/mod_authz_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/mod_authz_svn/mod_authz_svn.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/mod_authz_svn/mod_authz_svn.c (original)
+++ subversion/branches/patch-exec/subversion/mod_authz_svn/mod_authz_svn.c Wed Aug 19 02:35:12 2015
@@ -84,20 +84,18 @@ typedef struct authz_svn_config_rec {
   const char *force_username_case;
 } authz_svn_config_rec;
 
-#if AP_MODULE_MAGIC_AT_LEAST(20060110,0) /* version where
-                                            ap_some_auth_required breaks */
-#  if AP_MODULE_MAGIC_AT_LEAST(20120211,47) /* first version with
-                                               force_authn hook and
-                                               ap_some_authn_required() which
-                                               allows us to work without
-                                               ap_some_auth_required() */
+/* version where ap_some_auth_required breaks */
+#if AP_MODULE_MAGIC_AT_LEAST(20060110,0)
+/* first version with force_authn hook and ap_some_authn_required()
+   which allows us to work without ap_some_auth_required() */
+#  if AP_MODULE_MAGIC_AT_LEAST(20120211,47) || defined(SVN_USE_FORCE_AUTHN)
 #    define USE_FORCE_AUTHN 1
 #    define IN_SOME_AUTHN_NOTE "authz_svn-in-some-authn"
 #    define FORCE_AUTHN_NOTE "authz_svn-force-authn"
 #  else 
      /* ap_some_auth_required() is busted and no viable alternative exists */
 #    ifndef SVN_ALLOW_BROKEN_HTTPD_AUTH
-#      error This version of httpd has a security hole with mod_authz_svn
+#      error This Apache httpd has broken auth (CVE-2015-3184)
 #    else
        /* user wants to build anyway */
 #      define USE_FORCE_AUTHN 0

Modified: subversion/branches/patch-exec/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/mod_dav_svn/repos.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/patch-exec/subversion/mod_dav_svn/repos.c Wed Aug 19 02:35:12 2015
@@ -2067,7 +2067,7 @@ parse_querystring(request_rec *r, const
         return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                     "Couldn't trace history.", pool);
 
-      newpath = apr_hash_get(locations, &working_rev, sizeof(svn_revnum_t));
+      newpath = apr_hash_get(locations, &working_rev, sizeof(working_rev));
       if (! newpath)
         return dav_svn__new_error(pool, HTTP_NOT_FOUND, 0, 0,
                                   "path doesn't exist in that revision.");

Modified: subversion/branches/patch-exec/subversion/svn/help-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/svn/help-cmd.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/svn/help-cmd.c (original)
+++ subversion/branches/patch-exec/subversion/svn/help-cmd.c Wed Aug 19 02:35:12 2015
@@ -53,8 +53,9 @@ svn_cl__help(apr_getopt_t *os,
   N_("usage: svn <subcommand> [options] [args]\n"
      "Subversion command-line client.\n"
      "Type 'svn help <subcommand>' for help on a specific subcommand.\n"
-     "Type 'svn --version' to see the program version and RA modules\n"
-     "  or 'svn --version --quiet' to see just the version number.\n"
+     "Type 'svn --version' to see the program version and RA modules,\n"
+     "     'svn --version --verbose' to see dependency versions as well,\n"
+     "     'svn --version --quiet' to see just the version number.\n"
      "\n"
      "Most subcommands take file and/or directory arguments, recursing\n"
      "on the directories.  If no arguments are supplied to such a\n"

Modified: subversion/branches/patch-exec/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/svnadmin/svnadmin.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/patch-exec/subversion/svnadmin/svnadmin.c Wed Aug 19 02:35:12 2015
@@ -166,11 +166,13 @@ static svn_opt_subcommand_t
   subcommand_delrevprop,
   subcommand_deltify,
   subcommand_dump,
+  subcommand_dump_revprops,
   subcommand_freeze,
   subcommand_help,
   subcommand_hotcopy,
   subcommand_info,
   subcommand_load,
+  subcommand_load_revprops,
   subcommand_list_dblogs,
   subcommand_list_unused_dblogs,
   subcommand_lock,
@@ -392,6 +394,15 @@ static const svn_opt_subcommand_desc2_t
     "changed in those revisions.)\n"),
   {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M'} },
 
+  {"dump-revprops", subcommand_dump_revprops, {0}, N_
+   ("usage: svnadmin dump-revprops REPOS_PATH [-r LOWER[:UPPER]]\n\n"
+    "Dump the revision properties of filesystem to stdout in a 'dumpfile'\n"
+    "portable format, sending feedback to stderr.  Dump revisions\n"
+    "LOWER rev through UPPER rev.  If no revisions are given, dump the\n"
+    "properties for all revisions.  If only LOWER is given, dump the\n"
+    "properties for that one revision.\n"),
+  {'r', 'q'} },
+
   {"freeze", subcommand_freeze, {0}, N_
    ("usage: 1. svnadmin freeze REPOS_PATH PROGRAM [ARG...]\n"
     "               2. svnadmin freeze -F FILE PROGRAM [ARG...]\n\n"
@@ -444,6 +455,15 @@ static const svn_opt_subcommand_desc2_t
     svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook,
     svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} },
 
+  {"load-revprops", subcommand_load_revprops, {0}, N_
+   ("usage: svnadmin load-revprops REPOS_PATH\n\n"
+    "Read a 'dumpfile'-formatted stream from stdin, setting the revision\n"
+    "properties in the repository's filesystem.  Revisions not found in the\n"
+    "repository will cause an error.  Progress feedback is sent to stdout.\n"
+    "If --revision is specified, limit the loaded revisions to only those\n"
+    "in the dump stream whose revision numbers match the specified range.\n"),
+   {'q', 'r', svnadmin__force_uuid, svnadmin__bypass_prop_validation} },
+
   {"lock", subcommand_lock, {0}, N_
    ("usage: svnadmin lock REPOS_PATH PATH USERNAME COMMENT-FILE [TOKEN]\n\n"
     "Lock PATH by USERNAME setting comments from COMMENT-FILE.\n"
@@ -1139,6 +1159,12 @@ repos_notify_handler(void *baton,
         }
       return;
 
+    case svn_repos_notify_load_revprop_set:
+      svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+                        _("Properties set on revision %ld.\n"),
+                        notify->new_revision));
+      return;
+
     default:
       return;
   }
@@ -1184,55 +1210,104 @@ recode_stream_create(FILE *std_stream, a
   return rw_stream;
 }
 
-
-/* This implements `svn_opt_subcommand_t'. */
+/* Read the min / max revision from the OPT_STATE, verify them against REPOS
+   and return them in *LOWER and *UPPER, respectively.  Use SCRATCH_POOL
+   for temporary allocations. */
 static svn_error_t *
-subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+get_dump_range(svn_revnum_t *lower,
+               svn_revnum_t *upper,
+               svn_repos_t *repos,
+               struct svnadmin_opt_state *opt_state,
+               apr_pool_t *scratch_pool)
 {
-  struct svnadmin_opt_state *opt_state = baton;
-  svn_repos_t *repos;
   svn_fs_t *fs;
-  svn_stream_t *stdout_stream;
-  svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
   svn_revnum_t youngest;
-  svn_stream_t *feedback_stream = NULL;
 
-  /* Expect no more arguments. */
-  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+  *lower = SVN_INVALID_REVNUM;
+  *upper = SVN_INVALID_REVNUM;
 
-  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
   fs = svn_repos_fs(repos);
-  SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
+  SVN_ERR(svn_fs_youngest_rev(&youngest, fs, scratch_pool));
 
   /* Find the revision numbers at which to start and end. */
-  SVN_ERR(get_revnum(&lower, &opt_state->start_revision,
-                     youngest, repos, pool));
-  SVN_ERR(get_revnum(&upper, &opt_state->end_revision,
-                     youngest, repos, pool));
+  SVN_ERR(get_revnum(lower, &opt_state->start_revision,
+                     youngest, repos, scratch_pool));
+  SVN_ERR(get_revnum(upper, &opt_state->end_revision,
+                     youngest, repos, scratch_pool));
 
   /* Fill in implied revisions if necessary. */
-  if (lower == SVN_INVALID_REVNUM)
+  if (*lower == SVN_INVALID_REVNUM)
     {
-      lower = 0;
-      upper = youngest;
+      *lower = 0;
+      *upper = youngest;
     }
-  else if (upper == SVN_INVALID_REVNUM)
+  else if (*upper == SVN_INVALID_REVNUM)
     {
-      upper = lower;
+      *upper = *lower;
     }
 
-  if (lower > upper)
+  if (*lower > *upper)
     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
        _("First revision cannot be higher than second"));
 
+  return SVN_NO_ERROR;
+}
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnadmin_opt_state *opt_state = baton;
+  svn_repos_t *repos;
+  svn_stream_t *stdout_stream;
+  svn_revnum_t lower, upper;
+  svn_stream_t *feedback_stream = NULL;
+
+  /* Expect no more arguments. */
+  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+  SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool));
+
   SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
 
   /* Progress feedback goes to STDERR, unless they asked to suppress it. */
   if (! opt_state->quiet)
     feedback_stream = recode_stream_create(stderr, pool);
 
-  SVN_ERR(svn_repos_dump_fs3(repos, stdout_stream, lower, upper,
+  SVN_ERR(svn_repos_dump_fs4(repos, stdout_stream, lower, upper,
                              opt_state->incremental, opt_state->use_deltas,
+                             TRUE, TRUE,
+                             !opt_state->quiet ? repos_notify_handler : NULL,
+                             feedback_stream, check_cancel, NULL, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_dump_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnadmin_opt_state *opt_state = baton;
+  svn_repos_t *repos;
+  svn_stream_t *stdout_stream;
+  svn_revnum_t lower, upper;
+  svn_stream_t *feedback_stream = NULL;
+
+  /* Expect no more arguments. */
+  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+  SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool));
+
+  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+
+  /* Progress feedback goes to STDERR, unless they asked to suppress it. */
+  if (! opt_state->quiet)
+    feedback_stream = recode_stream_create(stderr, pool);
+
+  SVN_ERR(svn_repos_dump_fs4(repos, stdout_stream, lower, upper,
+                             FALSE, FALSE, TRUE, FALSE,
                              !opt_state->quiet ? repos_notify_handler : NULL,
                              feedback_stream, check_cancel, NULL, pool));
 
@@ -1374,43 +1449,57 @@ optrev_to_revnum(svn_revnum_t *revnum, c
   return SVN_NO_ERROR;
 }
 
-
-/* This implements `svn_opt_subcommand_t'. */
+/* Read the min / max revision from the OPT_STATE, verify them and return
+   them in *LOWER and *UPPER, respectively. */
 static svn_error_t *
-subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+get_load_range(svn_revnum_t *lower,
+               svn_revnum_t *upper,
+               struct svnadmin_opt_state *opt_state)
 {
-  svn_error_t *err;
-  struct svnadmin_opt_state *opt_state = baton;
-  svn_repos_t *repos;
-  svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
-  svn_stream_t *stdin_stream;
-  svn_stream_t *feedback_stream = NULL;
-
-  /* Expect no more arguments. */
-  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
-
   /* Find the revision numbers at which to start and end.  We only
      support a limited set of revision kinds: number and unspecified. */
-  SVN_ERR(optrev_to_revnum(&lower, &opt_state->start_revision));
-  SVN_ERR(optrev_to_revnum(&upper, &opt_state->end_revision));
+  SVN_ERR(optrev_to_revnum(lower, &opt_state->start_revision));
+  SVN_ERR(optrev_to_revnum(upper, &opt_state->end_revision));
 
   /* Fill in implied revisions if necessary. */
-  if ((upper == SVN_INVALID_REVNUM) && (lower != SVN_INVALID_REVNUM))
+  if ((*upper == SVN_INVALID_REVNUM) && (*lower != SVN_INVALID_REVNUM))
     {
-      upper = lower;
+      *upper = *lower;
     }
-  else if ((upper != SVN_INVALID_REVNUM) && (lower == SVN_INVALID_REVNUM))
+  else if ((*upper != SVN_INVALID_REVNUM) && (*lower == SVN_INVALID_REVNUM))
     {
-      lower = upper;
+      *lower = *upper;
     }
 
   /* Ensure correct range ordering. */
-  if (lower > upper)
+  if (*lower > *upper)
     {
       return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                               _("First revision cannot be higher than second"));
     }
 
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  svn_error_t *err;
+  struct svnadmin_opt_state *opt_state = baton;
+  svn_repos_t *repos;
+  svn_revnum_t lower, upper;
+  svn_stream_t *stdin_stream;
+  svn_stream_t *feedback_stream = NULL;
+
+  /* Expect no more arguments. */
+  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+  /* Find the revision numbers at which to start and end.  We only
+     support a limited set of revision kinds: number and unspecified. */
+  SVN_ERR(get_load_range(&lower, &upper, opt_state));
+
   SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
 
   /* Read the stream from STDIN.  Users can redirect a file. */
@@ -1437,6 +1526,47 @@ subcommand_load(apr_getopt_t *os, void *
   return err;
 }
 
+static svn_error_t *
+subcommand_load_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  svn_error_t *err;
+  struct svnadmin_opt_state *opt_state = baton;
+  svn_repos_t *repos;
+  svn_revnum_t lower, upper;
+  svn_stream_t *stdin_stream;
+
+  svn_stream_t *feedback_stream = NULL;
+
+  /* Expect no more arguments. */
+  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+  /* Find the revision numbers at which to start and end.  We only
+     support a limited set of revision kinds: number and unspecified. */
+  SVN_ERR(get_load_range(&lower, &upper, opt_state));
+
+  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
+
+  /* Read the stream from STDIN.  Users can redirect a file. */
+  SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
+
+  /* Progress feedback goes to STDOUT, unless they asked to suppress it. */
+  if (! opt_state->quiet)
+    feedback_stream = recode_stream_create(stdout, pool);
+
+  err = svn_repos_load_fs_revprops(repos, stdin_stream, lower, upper,
+                                   !opt_state->bypass_prop_validation,
+                                   opt_state->ignore_dates,
+                                   opt_state->quiet ? NULL
+                                                    : repos_notify_handler,
+                                   feedback_stream, check_cancel, NULL, pool);
+  if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
+    return svn_error_quick_wrap(err,
+                                _("Invalid property value found in "
+                                  "dumpstream; consider repairing the source "
+                                  "or using --bypass-prop-validation while "
+                                  "loading."));
+  return err;
+}
 
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *

Modified: subversion/branches/patch-exec/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/svndumpfilter/svndumpfilter.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/patch-exec/subversion/svndumpfilter/svndumpfilter.c Wed Aug 19 02:35:12 2015
@@ -640,7 +640,7 @@ new_node_record(void **node_baton,
               cf_orig_rev = SVN_STR_TO_REV(val);
               cf_renum_val = apr_hash_get(pb->renumber_history,
                                           &cf_orig_rev,
-                                          sizeof(svn_revnum_t));
+                                          sizeof(cf_orig_rev));
               if (! (cf_renum_val && SVN_IS_VALID_REVNUM(cf_renum_val->rev)))
                 return svn_error_createf
                   (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
@@ -730,14 +730,14 @@ adjust_mergeinfo(svn_string_t **final_va
                                                        svn_merge_range_t *);
 
               revmap_start = apr_hash_get(pb->renumber_history,
-                                          &range->start, sizeof(svn_revnum_t));
+                                          &range->start, sizeof(range->start));
               if (! (revmap_start && SVN_IS_VALID_REVNUM(revmap_start->rev)))
                 return svn_error_createf
                   (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                    _("No valid revision range 'start' in filtered stream"));
 
               revmap_end = apr_hash_get(pb->renumber_history,
-                                        &range->end, sizeof(svn_revnum_t));
+                                        &range->end, sizeof(range->end));
               if (! (revmap_end && SVN_IS_VALID_REVNUM(revmap_end->rev)))
                 return svn_error_createf
                   (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,

Modified: subversion/branches/patch-exec/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/svnrdump/load_editor.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/patch-exec/subversion/svnrdump/load_editor.c Wed Aug 19 02:35:12 2015
@@ -167,8 +167,7 @@ set_revision_mapping(apr_hash_t *rev_map
                                          sizeof(svn_revnum_t) * 2);
   mapped_revs[0] = from_rev;
   mapped_revs[1] = to_rev;
-  apr_hash_set(rev_map, mapped_revs,
-               sizeof(svn_revnum_t), mapped_revs + 1);
+  apr_hash_set(rev_map, mapped_revs, sizeof(*mapped_revs), mapped_revs + 1);
 }
 
 /* Return the revision to which FROM_REV maps in REV_MAP, or

Modified: subversion/branches/patch-exec/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/svnserve/svnserve.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/patch-exec/subversion/svnserve/svnserve.c Wed Aug 19 02:35:12 2015
@@ -211,6 +211,17 @@ void winservice_notify_stop(void)
 #define SVNSERVE_OPT_MAX_THREADS     272
 #define SVNSERVE_OPT_BLOCK_READ      273
 
+/* Text macro because we can't use #ifdef sections inside a N_("...")
+   macro expansion. */
+#ifdef CONNECTION_HAVE_THREAD_OPTION
+#define ONLY_AVAILABLE_WITH_THEADS \
+        "\n" \
+        "                             "\
+        "[used only with --threads]"
+#else
+#define ONLY_AVAILABLE_WITH_THEADS ""
+#endif
+
 static const apr_getopt_option_t svnserve__options[] =
   {
     {"daemon",           'd', 0, N_("daemon mode")},
@@ -317,22 +328,22 @@ static const apr_getopt_option_t svnserv
      * ### this option never exists when --service exists. */
     {"threads",          'T', 0, N_("use threads instead of fork "
                                     "[mode: daemon]")},
+#endif
+#if APR_HAS_THREADS
     {"min-threads",      SVNSERVE_OPT_MIN_THREADS, 1,
      N_("Minimum number of server threads, even if idle.\n"
         "                             "
         "Capped to max-threads; minimum value is 0.\n"
         "                             "
-        "Default is 1.\n"
-        "                             "
-        "[used only with --threads]")},
+        "Default is 1."
+        ONLY_AVAILABLE_WITH_THEADS)},
     {"max-threads",      SVNSERVE_OPT_MAX_THREADS, 1,
      N_("Maximum number of server threads, even if there\n"
         "                             "
         "are more connections.  Minimum value is 1.\n"
         "                             "
-        "Default is " APR_STRINGIFY(THREADPOOL_MAX_SIZE) ".\n"
-        "                             "
-        "[used only with --threads]")},
+        "Default is " APR_STRINGIFY(THREADPOOL_MAX_SIZE) "."
+        ONLY_AVAILABLE_WITH_THEADS)},
 #endif
     {"foreground",        SVNSERVE_OPT_FOREGROUND, 0,
      N_("run in foreground (useful for debugging)\n"

Modified: subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original)
+++ subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Wed Aug 19 02:35:12 2015
@@ -1,8 +1,9 @@
 usage: svn <subcommand> [options] [args]
 Subversion command-line client.
 Type 'svn help <subcommand>' for help on a specific subcommand.
-Type 'svn --version' to see the program version and RA modules
-  or 'svn --version --quiet' to see just the version number.
+Type 'svn --version' to see the program version and RA modules,
+     'svn --version --verbose' to see dependency versions as well,
+     'svn --version --quiet' to see just the version number.
 
 Most subcommands take file and/or directory arguments, recursing
 on the directories.  If no arguments are supplied to such a

Modified: subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original)
+++ subversion/branches/patch-exec/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Wed Aug 19 02:35:12 2015
@@ -1,8 +1,9 @@
 usage: svn <subcommand> [options] [args]
 Subversion command-line client.
 Type 'svn help <subcommand>' for help on a specific subcommand.
-Type 'svn --version' to see the program version and RA modules
-  or 'svn --version --quiet' to see just the version number.
+Type 'svn --version' to see the program version and RA modules,
+     'svn --version --verbose' to see dependency versions as well,
+     'svn --version --quiet' to see just the version number.
 
 Most subcommands take file and/or directory arguments, recursing
 on the directories.  If no arguments are supplied to such a

Modified: subversion/branches/patch-exec/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/cmdline/patch_tests.py?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/patch-exec/subversion/tests/cmdline/patch_tests.py Wed Aug 19 02:35:12 2015
@@ -2996,11 +2996,11 @@ def patch_git_empty_files(sbox):
     "Index: new\n",
     "===================================================================\n",
     "diff --git a/new b/new\n",
-    "new file mode 10644\n",
+    "new file mode 100644\n",
     "Index: iota\n",
     "===================================================================\n",
     "diff --git a/iota b/iota\n",
-    "deleted file mode 10644\n",
+    "deleted file mode 100644\n",
   ]
 
   svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))

Modified: subversion/branches/patch-exec/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/cmdline/svnadmin_tests.py?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/patch-exec/subversion/tests/cmdline/svnadmin_tests.py Wed Aug 19 02:35:12 2015
@@ -2743,7 +2743,10 @@ def verify_quickly(sbox):
   "verify quickly using metadata"
 
   sbox.build(create_wc = False)
-  rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b')
+  if svntest.main.is_fs_type_fsfs():
+    rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b')
+  else:
+    rev_file = open(fsfs_file(sbox.repo_dir, 'revs', 'r1'), 'r+b')
 
   # set new contents
   rev_file.seek(8)

Modified: subversion/branches/patch-exec/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/cmdline/svntest/verify.py?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/patch-exec/subversion/tests/cmdline/svntest/verify.py Wed Aug 19 02:35:12 2015
@@ -853,7 +853,7 @@ def make_git_diff_header(target_path, re
   if add:
     output.extend([
       "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n",
-      "new file mode 10644\n",
+      "new file mode 100644\n",
     ])
     if text_changes:
       output.extend([
@@ -863,7 +863,7 @@ def make_git_diff_header(target_path, re
   elif delete:
     output.extend([
       "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n",
-      "deleted file mode 10644\n",
+      "deleted file mode 100644\n",
     ])
     if text_changes:
       output.extend([

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_fs/fs-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_fs/fs-test.c Wed Aug 19 02:35:12 2015
@@ -5345,20 +5345,20 @@ test_fs_info_format(const svn_test_opts_
   int fs_format;
   svn_version_t *supports_version;
   svn_version_t v1_5_0 = {1, 5, 0, ""};
-  svn_version_t v1_9_0 = {1, 9, 0, ""};
+  svn_version_t v1_10_0 = {1, 10, 0, ""};
   svn_test_opts_t opts2;
   svn_boolean_t is_fsx = strcmp(opts->fs_type, "fsx") == 0;
 
   opts2 = *opts;
-  opts2.server_minor_version = is_fsx ? 9 : 5;
+  opts2.server_minor_version = is_fsx ? 10 : 5;
 
   SVN_ERR(svn_test__create_fs(&fs, "test-fs-format-info", &opts2, pool));
   SVN_ERR(svn_fs_info_format(&fs_format, &supports_version, fs, pool, pool));
 
   if (is_fsx)
     {
-      SVN_TEST_ASSERT(fs_format == 1);
-      SVN_TEST_ASSERT(svn_ver_equal(supports_version, &v1_9_0));
+      SVN_TEST_ASSERT(fs_format == 2);
+      SVN_TEST_ASSERT(svn_ver_equal(supports_version, &v1_10_0));
     }
   else
     {

Propchange: subversion/branches/patch-exec/subversion/tests/libsvn_fs_x/
            ('svn:mergeinfo' removed)

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_fs_x/fs-x-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_fs_x/fs-x-pack-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_fs_x/fs-x-pack-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_fs_x/fs-x-pack-test.c Wed Aug 19 02:35:12 2015
@@ -25,6 +25,7 @@
 #include <apr_pools.h>
 
 #include "../svn_test.h"
+#include "../../libsvn_fs_x/batch_fsync.h"
 #include "../../libsvn_fs_x/fs.h"
 #include "../../libsvn_fs_x/reps.h"
 
@@ -657,8 +658,8 @@ recover_fully_packed(const svn_test_opts
   /* Now, delete the youngest revprop file, and recover again.  This
      time we want to see an error! */
   SVN_ERR(svn_io_remove_file2(
-              svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR,
-                                   apr_psprintf(pool, "%ld/%ld",
+              svn_dirent_join_many(pool, REPO_NAME, PATH_REVS_DIR,
+                                   apr_psprintf(pool, "%ld/p%ld",
                                                 after_rev / SHARD_SIZE,
                                                 after_rev),
                                    SVN_VA_NULL),
@@ -844,6 +845,93 @@ pack_shard_size_one(const svn_test_opts_
 #undef SHARD_SIZE
 #undef MAX_REV
 /* ------------------------------------------------------------------------ */
+#define REPO_NAME "test-repo-fsx-batch-fsync"
+static svn_error_t *
+test_batch_fsync(const svn_test_opts_t *opts,
+                 apr_pool_t *pool)
+{
+  const char *abspath;
+  svn_fs_x__batch_fsync_t *batch;
+  int i;
+
+  /* Disable this test for non FSX backends because it has no relevance to
+   * them. */
+  if (strcmp(opts->fs_type, "fsx") != 0)
+      return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+      "this will test FSX repositories only");
+
+  /* Create an empty working directory and let it be cleaned up by the test
+   * harness. */
+  SVN_ERR(svn_dirent_get_absolute(&abspath, REPO_NAME, pool));
+
+  SVN_ERR(svn_io_remove_dir2(abspath, TRUE, NULL, NULL, pool));
+  SVN_ERR(svn_io_make_dir_recursively(abspath, pool));
+  svn_test_add_dir_cleanup(abspath);
+
+  /* Initialize infrastructure with a pool that lives as long as this
+   * application. */
+  SVN_ERR(svn_fs_x__batch_fsync_init());
+
+  /* We use and re-use the same batch object throughout this test. */
+  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, pool));
+
+  /* The working directory is new. */
+  SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, abspath, pool));
+
+  /* 1st run: Has to fire up worker threads etc. */
+  for (i = 0; i < 10; ++i)
+    {
+      apr_file_t *file;
+      const char *path = svn_dirent_join(abspath,
+                                         apr_psprintf(pool, "file%i", i),
+                                         pool);
+      apr_size_t len = strlen(path);
+
+      SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool));
+      SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool));
+
+      SVN_ERR(svn_io_file_write(file, path, &len, pool));
+    }
+
+  SVN_ERR(svn_fs_x__batch_fsync_run(batch, pool));
+
+  /* 2nd run: Running a batch must leave the container in an empty,
+   * re-usable state. Hence, try to re-use it. */
+  for (i = 0; i < 10; ++i)
+    {
+      apr_file_t *file;
+      const char *path = svn_dirent_join(abspath,
+                                         apr_psprintf(pool, "new%i", i),
+                                         pool);
+      apr_size_t len = strlen(path);
+
+      SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool));
+      SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool));
+
+      SVN_ERR(svn_io_file_write(file, path, &len, pool));
+    }
+
+  SVN_ERR(svn_fs_x__batch_fsync_run(batch, pool));
+
+  /* 3rd run: Schedule but don't execute. POOL cleanup shall not fail. */
+  for (i = 0; i < 10; ++i)
+    {
+      apr_file_t *file;
+      const char *path = svn_dirent_join(abspath,
+                                         apr_psprintf(pool, "another%i", i),
+                                         pool);
+      apr_size_t len = strlen(path);
+
+      SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool));
+      SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool));
+
+      SVN_ERR(svn_io_file_write(file, path, &len, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+#undef REPO_NAME
+/* ------------------------------------------------------------------------ */
 
 /* The test table.  */
 
@@ -876,6 +964,8 @@ static struct svn_test_descriptor_t test
                        "test representations container"),
     SVN_TEST_OPTS_PASS(pack_shard_size_one,
                        "test packing with shard size = 1"),
+    SVN_TEST_OPTS_PASS(test_batch_fsync,
+                       "test batch fsync"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_ra/ra-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_ra/ra-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_ra/ra-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_ra/ra-test.c Wed Aug 19 02:35:12 2015
@@ -332,15 +332,16 @@ static svn_error_t *
 check_tunnel_callback_test(const svn_test_opts_t *opts,
                            apr_pool_t *pool)
 {
-  tunnel_baton_t b = { TUNNEL_MAGIC };
+  tunnel_baton_t *b = apr_pcalloc(pool, sizeof(*b));
   svn_ra_callbacks2_t *cbtable;
   svn_ra_session_t *session;
-  svn_error_t *err;
+
+  b->magic = TUNNEL_MAGIC;
 
   SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
   cbtable->check_tunnel_func = check_tunnel;
   cbtable->open_tunnel_func = open_tunnel;
-  cbtable->tunnel_baton = &b;
+  cbtable->tunnel_baton = b;
   SVN_ERR(svn_cmdline_create_auth_baton2(&cbtable->auth_baton,
                                          TRUE  /* non_interactive */,
                                          "jrandom", "rayjandom",
@@ -350,12 +351,12 @@ check_tunnel_callback_test(const svn_tes
                                          FALSE, FALSE, FALSE, FALSE,
                                          NULL, NULL, NULL, pool));
 
-  b.last_check = TRUE;
-  err = svn_ra_open4(&session, NULL, "svn+foo://localhost/no-repo",
-                     NULL, cbtable, NULL, NULL, pool);
-  svn_error_clear(err);
-  SVN_TEST_ASSERT(err);
-  SVN_TEST_ASSERT(!b.last_check);
+  b->last_check = TRUE;
+  SVN_TEST_ASSERT_ERROR(svn_ra_open4(&session, NULL,
+                                     "svn+foo://localhost/no-repo",
+                                     NULL, cbtable, NULL, NULL, pool),
+                        SVN_ERR_RA_CANNOT_CREATE_SESSION);
+  SVN_TEST_ASSERT(!b->last_check);
   return SVN_NO_ERROR;
 }
 
@@ -363,14 +364,15 @@ static svn_error_t *
 tunnel_callback_test(const svn_test_opts_t *opts,
                      apr_pool_t *pool)
 {
-  tunnel_baton_t b = { TUNNEL_MAGIC };
+  tunnel_baton_t *b = apr_pcalloc(pool, sizeof(*b));
   apr_pool_t *scratch_pool = svn_pool_create(pool);
   const char *url;
   svn_ra_callbacks2_t *cbtable;
   svn_ra_session_t *session;
-  svn_error_t *err;
   const char tunnel_repos_name[] = "test-repo-tunnel";
 
+  b->magic = TUNNEL_MAGIC;
+
   SVN_ERR(svn_test__create_repos(NULL, tunnel_repos_name, opts, scratch_pool));
 
   /* Immediately close the repository to avoid race condition with svnserve
@@ -382,7 +384,7 @@ tunnel_callback_test(const svn_test_opts
   SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
   cbtable->check_tunnel_func = check_tunnel;
   cbtable->open_tunnel_func = open_tunnel;
-  cbtable->tunnel_baton = &b;
+  cbtable->tunnel_baton = b;
   SVN_ERR(svn_cmdline_create_auth_baton2(&cbtable->auth_baton,
                                          TRUE  /* non_interactive */,
                                          "jrandom", "rayjandom",
@@ -392,20 +394,13 @@ tunnel_callback_test(const svn_test_opts
                                          FALSE, FALSE, FALSE, FALSE,
                                          NULL, NULL, NULL, pool));
 
-  b.last_check = FALSE;
-  err = svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
-                     scratch_pool);
-  if (err && err->apr_err == SVN_ERR_TEST_FAILED)
-    {
-      svn_handle_error2(err, stderr, FALSE, "svn_tests: ");
-      svn_error_clear(err);
-      return SVN_NO_ERROR;
-    }
-  SVN_ERR(err);
-  SVN_TEST_ASSERT(b.last_check);
-  SVN_TEST_ASSERT(b.open_count > 0);
+  b->last_check = FALSE;
+  SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
+                        scratch_pool));
+  SVN_TEST_ASSERT(b->last_check);
+  SVN_TEST_ASSERT(b->open_count > 0);
   svn_pool_destroy(scratch_pool);
-  SVN_TEST_ASSERT(b.open_count == 0);
+  SVN_TEST_ASSERT(b->open_count == 0);
   return SVN_NO_ERROR;
 }
 
@@ -1517,6 +1512,66 @@ ra_list_has_props(const svn_test_opts_t
   return SVN_NO_ERROR;
 }
 
+/* Test ra_svn tunnel editor handling, including polling. */
+
+static svn_error_t *
+tunnel_run_checkout(const svn_test_opts_t *opts,
+                       apr_pool_t *pool)
+{
+  tunnel_baton_t *b = apr_pcalloc(pool, sizeof(*b));
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
+  const char *url;
+  svn_ra_callbacks2_t *cbtable;
+  svn_ra_session_t *session;
+  const char tunnel_repos_name[] = "test-run_checkout";
+  svn_ra_reporter3_t *reporter;
+  void *report_baton;
+
+  b->magic = TUNNEL_MAGIC;
+
+  SVN_ERR(svn_test__create_repos(NULL, tunnel_repos_name, opts, scratch_pool));
+
+  /* Immediately close the repository to avoid race condition with svnserve
+  (and then the cleanup code) with BDB when our pool is cleared. */
+  svn_pool_clear(scratch_pool);
+
+  url = apr_pstrcat(pool, "svn+test://localhost/", tunnel_repos_name,
+    SVN_VA_NULL);
+  SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
+  cbtable->check_tunnel_func = check_tunnel;
+  cbtable->open_tunnel_func = open_tunnel;
+  cbtable->tunnel_baton = b;
+  SVN_ERR(svn_cmdline_create_auth_baton2(&cbtable->auth_baton,
+    TRUE  /* non_interactive */,
+    "jrandom", "rayjandom",
+    NULL,
+    TRUE  /* no_auth_cache */,
+    FALSE /* trust_server_cert */,
+    FALSE, FALSE, FALSE, FALSE,
+    NULL, NULL, NULL, pool));
+
+  b->last_check = FALSE;
+
+  SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
+                       scratch_pool));
+
+  SVN_ERR(commit_changes(session, pool));
+
+  SVN_ERR(svn_ra_do_update3(session,
+                            &reporter, &report_baton,
+                            1, "",
+                            svn_depth_infinity, FALSE, FALSE,
+                            svn_delta_default_editor(pool), NULL,
+                            pool, pool));
+
+  SVN_ERR(reporter->set_path(report_baton, "", 0, svn_depth_infinity, FALSE,
+                             NULL, pool));
+
+  SVN_ERR(reporter->finish_report(report_baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* The test table.  */
 
@@ -1547,6 +1602,8 @@ static struct svn_test_descriptor_t test
                        "check how ra layers handle errors from callbacks"),
     SVN_TEST_OPTS_PASS(ra_list_has_props,
                        "check list has_props performance"),
+    SVN_TEST_OPTS_PASS(tunnel_run_checkout,
+                       "verify checkout over a tunnel"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_repos/dump-load-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_repos/dump-load-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_repos/dump-load-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_repos/dump-load-test.c Wed Aug 19 02:35:12 2015
@@ -76,8 +76,8 @@ test_dump_bad_props(svn_stringbuf_t **du
   SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
 
   /* Test that a dump completes without error. */
-  SVN_ERR(svn_repos_dump_fs3(repos, stream, start_rev, end_rev,
-                             FALSE, FALSE,
+  SVN_ERR(svn_repos_dump_fs4(repos, stream, start_rev, end_rev,
+                             FALSE, FALSE, TRUE, TRUE,
                              notify_func, notify_baton,
                              NULL, NULL,
                              pool));

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_repos/repos-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_repos/repos-test.c Wed Aug 19 02:35:12 2015
@@ -750,8 +750,7 @@ check_locations_info(apr_hash_t *locatio
   unsigned int i;
   for (i = 0; info->rev != 0; ++i, ++info)
     {
-      const char *p = apr_hash_get(locations, &info->rev, sizeof
-                                   (svn_revnum_t));
+      const char *p = apr_hash_get(locations, &info->rev, sizeof(info->rev));
       if (!p)
         return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
                                  "Missing path for revision %ld", info->rev);
@@ -2999,7 +2998,7 @@ file_rev_handler(void *baton, const char
 {
   apr_hash_t *ht = baton;
   const char *author;
-  file_revs_t *file_rev = apr_hash_get(ht, &rev, sizeof(svn_revnum_t));
+  file_revs_t *file_rev = apr_hash_get(ht, &rev, sizeof(rev));
 
   if (!file_rev)
     return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
@@ -3017,7 +3016,7 @@ file_rev_handler(void *baton, const char
 
   /* Remove this revision from this list so we'll be able to verify that we
      have seen all expected revisions. */
-  apr_hash_set(ht, &rev, sizeof(svn_revnum_t), NULL);
+  apr_hash_set(ht, &rev, sizeof(rev), NULL);
 
   return SVN_NO_ERROR;
 }
@@ -3055,16 +3054,16 @@ test_get_file_revs(const svn_test_opts_t
 
   for (i = 0; i < sizeof(trunk_results) / sizeof(trunk_results[0]); i++)
     apr_hash_set(ht_trunk_results, &trunk_results[i].rev,
-                 sizeof(svn_revnum_t), &trunk_results[i]);
+                 sizeof(trunk_results[i].rev), &trunk_results[i]);
 
   for (i = 0; i < sizeof(branch_results) / sizeof(branch_results[0]); i++)
     apr_hash_set(ht_branch_results, &branch_results[i].rev,
-                 sizeof(svn_revnum_t), &branch_results[i]);
+                 sizeof(branch_results[i].rev), &branch_results[i]);
 
   for (i = 0; i < sizeof(trunk_results) / sizeof(trunk_results[0]); i++)
     if (!trunk_results[i].result_of_merge)
       apr_hash_set(ht_reverse_results, &trunk_results[i].rev,
-                   sizeof(svn_revnum_t), &trunk_results[i]);
+                   sizeof(trunk_results[i].rev), &trunk_results[i]);
 
   /* Check for feature support */
   if (opts->server_minor_version && (opts->server_minor_version < 5))
@@ -3680,7 +3679,7 @@ verify_locations(apr_hash_t *actual,
   for (hi = apr_hash_first(pool, expected); hi; hi = apr_hash_next(hi))
     {
       const svn_revnum_t *rev = apr_hash_this_key(hi);
-      const char *path = apr_hash_get(actual, rev, sizeof(svn_revnum_t));
+      const char *path = apr_hash_get(actual, rev, sizeof(*rev));
 
       if (!path)
         return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
@@ -3696,7 +3695,7 @@ verify_locations(apr_hash_t *actual,
   for (hi = apr_hash_first(pool, actual); hi; hi = apr_hash_next(hi))
     {
       const svn_revnum_t *rev = apr_hash_this_key(hi);
-      const char *path = apr_hash_get(expected, rev, sizeof(svn_revnum_t));
+      const char *path = apr_hash_get(expected, rev, sizeof(*rev));
 
       if (!path)
         return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
@@ -3723,7 +3722,7 @@ set_expected(apr_hash_t *expected,
 {
   svn_revnum_t *rp = apr_palloc(pool, sizeof(svn_revnum_t));
   *rp = rev;
-  apr_hash_set(expected, rp, sizeof(svn_revnum_t), path);
+  apr_hash_set(expected, rp, sizeof(*rp), path);
 }
 
 static svn_error_t *

Modified: subversion/branches/patch-exec/subversion/tests/libsvn_subr/cache-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_subr/cache-test.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/tests/libsvn_subr/cache-test.c (original)
+++ subversion/branches/patch-exec/subversion/tests/libsvn_subr/cache-test.c Wed Aug 19 02:35:12 2015
@@ -221,6 +221,7 @@ test_membuffer_cache_basic(apr_pool_t *p
                                             "cache:",
                                             SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
                                             FALSE,
+                                            FALSE,
                                             pool, pool));
 
   return basic_cache_test(cache, FALSE, pool);
@@ -278,6 +279,7 @@ test_membuffer_serializer_error_handling
                                             "cache:",
                                             SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
                                             FALSE,
+                                            FALSE,
                                             pool, pool));
 
   SVN_ERR(svn_cache__set(cache, "twenty", &twenty, pool));
@@ -307,6 +309,7 @@ test_membuffer_serializer_error_handling
                                             "cache:",
                                             SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
                                             FALSE,
+                                            FALSE,
                                             pool, pool));
 
   /* Store one entry in cache. */
@@ -393,6 +396,7 @@ test_membuffer_cache_clearing(apr_pool_t
                                             "cache:",
                                             SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
                                             FALSE,
+                                            FALSE,
                                             pool, pool));
 
   /* Initially, the cache is empty. */
@@ -440,6 +444,51 @@ test_membuffer_cache_clearing(apr_pool_t
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_iter_apr_hash_cb_t. */
+static svn_error_t *
+null_cache_iter_func(void *baton,
+                     const void *key,
+                     apr_ssize_t klen,
+                     void *val,
+                     apr_pool_t *pool)
+{
+  /* shall never be called */
+  return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "should not be called");
+}
+
+static svn_error_t *
+test_null_cache(apr_pool_t *pool)
+{
+  svn_boolean_t found, done;
+  int *data = NULL;
+  svn_cache__info_t info;
+
+  svn_cache__t *cache;
+  SVN_ERR(svn_cache__create_null(&cache, "test-dummy", pool));
+
+  /* Can't cache anything. */
+  SVN_TEST_ASSERT(svn_cache__is_cachable(cache, 0) == FALSE);
+  SVN_TEST_ASSERT(svn_cache__is_cachable(cache, 1) == FALSE);
+
+  /* No point in adding data. */
+  SVN_ERR(svn_cache__set(cache, "data", &data, pool));
+  SVN_ERR(svn_cache__get((void **)&data, &found, cache, "data", pool));
+  SVN_TEST_ASSERT(found == FALSE);
+
+  SVN_ERR(svn_cache__has_key(&found, cache, "data", pool));
+  SVN_TEST_ASSERT(found == FALSE);
+
+  /* Iteration "works" but is a no-op. */
+  SVN_ERR(svn_cache__iter(&done, cache, null_cache_iter_func, NULL, pool));
+  SVN_TEST_ASSERT(done);
+
+  /* It shall know its name. */
+  SVN_ERR(svn_cache__get_info(cache, &info, TRUE, pool));
+  SVN_TEST_STRING_ASSERT(info.id, "test-dummy");
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 test_membuffer_unaligned_string_keys(apr_pool_t *pool)
 {
@@ -462,7 +511,7 @@ test_membuffer_unaligned_string_keys(apr
   SVN_ERR(svn_cache__create_membuffer_cache(
             &cache, membuffer, serialize_revnum, deserialize_revnum,
             APR_HASH_KEY_STRING, unaligned_prefix,
-            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE,
+            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE, FALSE,
             pool, pool));
 
   SVN_ERR(svn_cache__set(cache, unaligned_key, &fifty, pool));
@@ -513,7 +562,7 @@ test_membuffer_unaligned_fixed_keys(apr_
             &cache, membuffer, serialize_revnum, deserialize_revnum,
             8 /* klen*/,
             unaligned_prefix,
-            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE,
+            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE, FALSE,
             pool, pool));
 
   SVN_ERR(svn_cache__set(cache, unaligned_key, &fifty, pool));
@@ -541,6 +590,7 @@ test_membuffer_unaligned_fixed_keys(apr_
   return SVN_NO_ERROR;
 }
 
+
 /* The test table.  */
 
 static int max_threads = 1;
@@ -560,6 +610,8 @@ static struct svn_test_descriptor_t test
                    "test for error handling in membuffer svn_cache"),
     SVN_TEST_PASS2(test_membuffer_cache_clearing,
                    "test clearing a membuffer svn_cache"),
+    SVN_TEST_PASS2(test_null_cache,
+                   "basic null svn_cache test"),
     SVN_TEST_PASS2(test_membuffer_unaligned_string_keys,
                    "test membuffer cache with unaligned string keys"),
     SVN_TEST_PASS2(test_membuffer_unaligned_fixed_keys,

Modified: subversion/branches/patch-exec/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh (original)
+++ subversion/branches/patch-exec/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh Wed Aug 19 02:35:12 2015
@@ -28,7 +28,7 @@ cd ../obj
 LD_PRELOAD_64=/export/home/wandisco/buildbot/install/lib/preloadable_libiconv.so
 export LD_PRELOAD_64
 
-if [ $SVN_VER_MINOR -eq 9 ]; then
+if [ $SVN_VER_MINOR -ge 9 ]; then
   echo "============ make svnserveautocheck"
   make svnserveautocheck CLEANUP=1 PARALLEL=30 THREADED=1 || exit $?
 else

Modified: subversion/branches/patch-exec/tools/client-side/bash_completion
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/tools/client-side/bash_completion?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/tools/client-side/bash_completion (original)
+++ subversion/branches/patch-exec/tools/client-side/bash_completion Wed Aug 19 02:35:12 2015
@@ -423,6 +423,7 @@ _svn()
 		else
 			# show schemas
 			COMPREPLY=( $(compgen -W "$urlSchemas" -- $cur) )
+			compopt -o nospace
 			return
 		fi
 	fi
@@ -440,10 +441,12 @@ _svn()
 	    elif [[ "$here" == */trunk* ]] ; then
 	      # we guess that it is a merge from a branch
 	      COMPREPLY=( $(compgen -W ${here/\/trunk*/\/branches\/} -- $cur ) )
+	      compopt -o nospace
 	      return 0
 	    else
 	      # no se, let us suggest the repository root...
-	      COMPREPLY=( $(compgen -W $(_svn_info Root) -- $cur ) )
+	      COMPREPLY=( $(compgen -W $(_svn_info Root)/ -- $cur ) )
+	      compopt -o nospace
 	      return 0
 	    fi
 	  elif [[ $URL == */branches/* && $here == */trunk* && \

Modified: subversion/branches/patch-exec/tools/dev/fsfs-access-map.c
URL: http://svn.apache.org/viewvc/subversion/branches/patch-exec/tools/dev/fsfs-access-map.c?rev=1696514&r1=1696513&r2=1696514&view=diff
==============================================================================
--- subversion/branches/patch-exec/tools/dev/fsfs-access-map.c (original)
+++ subversion/branches/patch-exec/tools/dev/fsfs-access-map.c Wed Aug 19 02:35:12 2015
@@ -225,7 +225,7 @@ open_file(const char *name, int handle)
       *key = handle;
 
       handle_info = apr_pcalloc(pool, sizeof(*handle_info));
-      apr_hash_set(handles, key, sizeof(handle), handle_info);
+      apr_hash_set(handles, key, sizeof(*key), handle_info);
     }
 
   /* link handle to file */