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

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

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c Mon Nov 30 10:24:16 2015
@@ -1657,8 +1657,14 @@ svn_fs_base__things_different(svn_boolea
 
   /* Compare contents keys and their (optional) uniquifiers. */
   if (contents_changed != NULL)
-    *contents_changed = (! svn_fs_base__same_keys(noderev1->data_key,
-                                                  noderev2->data_key));
+    *contents_changed =
+      (! (svn_fs_base__same_keys(noderev1->data_key,
+                                 noderev2->data_key)
+          /* Technically, these uniquifiers aren't used and "keys",
+             but keys are base-36 stringified numbers, so we'll take
+             this liberty. */
+          && (svn_fs_base__same_keys(noderev1->data_key_uniquifier,
+                                     noderev2->data_key_uniquifier))));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c Mon Nov 30 10:24:16 2015
@@ -471,6 +471,13 @@ bdb_write_config(svn_fs_t *fs)
 }
 
 static svn_error_t *
+base_bdb_refresh_revision(svn_fs_t *fs,
+                          apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 base_bdb_info_format(int *fs_format,
                      svn_version_t **supports_version,
                      svn_fs_t *fs,
@@ -545,6 +552,7 @@ base_bdb_freeze(svn_fs_t *fs,
 
 static fs_vtable_t fs_vtable = {
   svn_fs_base__youngest_rev,
+  base_bdb_refresh_revision,
   svn_fs_base__revision_prop,
   svn_fs_base__revision_proplist,
   svn_fs_base__change_rev_prop,
@@ -572,13 +580,12 @@ static fs_vtable_t fs_vtable = {
 #define FORMAT_FILE   "format"
 
 /* Depending on CREATE, create or open the environment and databases
-   for filesystem FS in PATH. Use POOL for temporary allocations. */
+   for filesystem FS in PATH. */
 static svn_error_t *
 open_databases(svn_fs_t *fs,
                svn_boolean_t create,
                int format,
-               const char *path,
-               apr_pool_t *pool)
+               const char *path)
 {
   base_fs_data_t *bfd;
 
@@ -732,7 +739,7 @@ static svn_error_t *
 base_create(svn_fs_t *fs,
             const char *path,
             svn_mutex__t *common_pool_lock,
-            apr_pool_t *pool,
+            apr_pool_t *scratch_pool,
             apr_pool_t *common_pool)
 {
   int format = SVN_FS_BASE__FORMAT_NUMBER;
@@ -743,7 +750,7 @@ base_create(svn_fs_t *fs,
     {
       svn_version_t *compatible_version;
       SVN_ERR(svn_fs__compatible_version(&compatible_version, fs->config,
-                                         pool));
+                                         scratch_pool));
 
       /* select format number */
       switch(compatible_version->minor)
@@ -765,7 +772,7 @@ base_create(svn_fs_t *fs,
     }
 
   /* Create the environment and databases. */
-  svn_err = open_databases(fs, TRUE, format, path, pool);
+  svn_err = open_databases(fs, TRUE, format, path);
   if (svn_err) goto error;
 
   /* Initialize the DAG subsystem. */
@@ -773,14 +780,15 @@ base_create(svn_fs_t *fs,
   if (svn_err) goto error;
 
   /* This filesystem is ready.  Stamp it with a format number. */
-  svn_err = svn_io_write_version_file(
-   svn_dirent_join(fs->path, FORMAT_FILE, pool), format, pool);
+  svn_err = svn_io_write_version_file(svn_dirent_join(fs->path, FORMAT_FILE,
+                                                      scratch_pool),
+                                      format, scratch_pool);
   if (svn_err) goto error;
 
   ((base_fs_data_t *) fs->fsap_data)->format = format;
 
-  SVN_ERR(populate_opened_fs(fs, pool));
-  return SVN_NO_ERROR;;
+  SVN_ERR(populate_opened_fs(fs, scratch_pool));
+  return SVN_NO_ERROR;
 
 error:
   return svn_error_compose_create(svn_err,
@@ -826,7 +834,7 @@ static svn_error_t *
 base_open(svn_fs_t *fs,
           const char *path,
           svn_mutex__t *common_pool_lock,
-          apr_pool_t *pool,
+          apr_pool_t *scratch_pool,
           apr_pool_t *common_pool)
 {
   int format;
@@ -835,8 +843,9 @@ base_open(svn_fs_t *fs,
 
   /* Read the FS format number. */
   svn_err = svn_io_read_version_file(&format,
-                                     svn_dirent_join(path, FORMAT_FILE, pool),
-                                     pool);
+                                     svn_dirent_join(path, FORMAT_FILE,
+                                                     scratch_pool),
+                                     scratch_pool);
   if (svn_err && APR_STATUS_IS_ENOENT(svn_err->apr_err))
     {
       /* Pre-1.2 filesystems did not have a format file (you could say
@@ -852,7 +861,7 @@ base_open(svn_fs_t *fs,
     goto error;
 
   /* Create the environment and databases. */
-  svn_err = open_databases(fs, FALSE, format, path, pool);
+  svn_err = open_databases(fs, FALSE, format, path);
   if (svn_err) goto error;
 
   ((base_fs_data_t *) fs->fsap_data)->format = format;
@@ -862,12 +871,12 @@ base_open(svn_fs_t *fs,
   if (write_format_file)
     {
       svn_err = svn_io_write_version_file(svn_dirent_join(path, FORMAT_FILE,
-                                                        pool),
-                                          format, pool);
+                                                        scratch_pool),
+                                          format, scratch_pool);
       if (svn_err) goto error;
     }
 
-  SVN_ERR(populate_opened_fs(fs, pool));
+  SVN_ERR(populate_opened_fs(fs, scratch_pool));
   return SVN_NO_ERROR;
 
  error:

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h Mon Nov 30 10:24:16 2015
@@ -195,11 +195,7 @@ typedef struct node_revision_t
      only because one or both of us decided to pick up a shared
      representation after-the-fact."  May be NULL (if this node
      revision isn't using a shared rep, or isn't the original
-     "assignee" of a shared rep).
-
-     This is no longer used by the 1.9 code but we have to keep
-     reading and writing it to remain compatible with 1.8, and
-     earlier, that require it. */
+     "assignee" of a shared rep). */
   const char *data_key_uniquifier;
 
   /* representation key for this node's text-data-in-progess (files

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/id.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/id.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/id.c Mon Nov 30 10:24:16 2015
@@ -113,7 +113,7 @@ svn_fs_base__id_compare(const svn_fs_id_
                         const svn_fs_id_t *b)
 {
   if (svn_fs_base__id_eq(a, b))
-    return svn_fs_node_same;
+    return svn_fs_node_unchanged;
   return (svn_fs_base__id_check_related(a, b) ? svn_fs_node_common_ancestor
                                               : svn_fs_node_unrelated);
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c Mon Nov 30 10:24:16 2015
@@ -39,6 +39,7 @@
 #include "private/svn_fs_util.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_dep_compat.h"
+#include "revs-txns.h"
 
 
 /* Add LOCK and its associated LOCK_TOKEN (associated with PATH) as
@@ -107,7 +108,7 @@ txn_body_lock(void *baton, trail_t *trai
   SVN_ERR(svn_fs_base__get_path_kind(&kind, args->path, trail, trail->pool));
 
   /* Until we implement directory locks someday, we only allow locks
-     on files or non-existent paths. */
+     on files. */
   if (kind == svn_node_dir)
     return SVN_FS__ERR_NOT_FILE(trail->fs, args->path);
 
@@ -241,8 +242,11 @@ svn_fs_base__lock(svn_fs_t *fs,
 {
   apr_hash_index_t *hi;
   svn_error_t *cb_err = SVN_NO_ERROR;
+  svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
+  SVN_ERR(svn_fs_base__youngest_rev(&youngest_rev, fs, scratch_pool));
 
   for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
     {
@@ -250,8 +254,9 @@ svn_fs_base__lock(svn_fs_t *fs,
       const char *path = apr_hash_this_key(hi);
       const svn_fs_lock_target_t *target = apr_hash_this_val(hi);
       svn_lock_t *lock;
-      svn_error_t *err;
+      svn_error_t *err = NULL;
 
+      svn_pool_clear(iterpool);
       args.lock_p = &lock;
       args.path = svn_fs__canonicalize_abspath(path, result_pool);
       args.token = target->token;
@@ -262,12 +267,22 @@ svn_fs_base__lock(svn_fs_t *fs,
       args.current_rev = target->current_rev;
       args.result_pool = result_pool;
 
-      err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, TRUE,
-                                   scratch_pool);
+      if (SVN_IS_VALID_REVNUM(target->current_rev))
+        {
+          if (target->current_rev > youngest_rev)
+            err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                                    _("No such revision %ld"),
+                                    target->current_rev);
+        }
+
+      if (!err)
+        err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, TRUE,
+                                     iterpool);
       if (!cb_err && lock_callback)
-        cb_err = lock_callback(lock_baton, args.path, lock, err, scratch_pool);
+        cb_err = lock_callback(lock_baton, args.path, lock, err, iterpool);
       svn_error_clear(err);
     }
+  svn_pool_destroy(iterpool);
 
   return svn_error_trace(cb_err);
 }
@@ -356,6 +371,7 @@ svn_fs_base__unlock(svn_fs_t *fs,
 {
   apr_hash_index_t *hi;
   svn_error_t *cb_err = SVN_NO_ERROR;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
@@ -366,16 +382,18 @@ svn_fs_base__unlock(svn_fs_t *fs,
       const char *token = apr_hash_this_val(hi);
       svn_error_t *err;
 
+      svn_pool_clear(iterpool);
       args.path = svn_fs__canonicalize_abspath(path, result_pool);
       args.token = token;
       args.break_lock = break_lock;
 
       err = svn_fs_base__retry_txn(fs, txn_body_unlock, &args, TRUE,
-                                   scratch_pool);
+                                   iterpool);
       if (!cb_err && lock_callback)
-        cb_err = lock_callback(lock_baton, path, NULL, err, scratch_pool);
+        cb_err = lock_callback(lock_baton, path, NULL, err, iterpool);
       svn_error_clear(err);
     }
+  svn_pool_destroy(iterpool);
 
   return svn_error_trace(cb_err);
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c Mon Nov 30 10:24:16 2015
@@ -194,7 +194,9 @@ svn_error_t *
 svn_fs_base__revision_proplist(apr_hash_t **table_p,
                                svn_fs_t *fs,
                                svn_revnum_t rev,
-                               apr_pool_t *pool)
+                               svn_boolean_t refresh,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
 {
   struct revision_proplist_args args;
   apr_hash_t *table;
@@ -204,9 +206,9 @@ svn_fs_base__revision_proplist(apr_hash_
   args.table_p = &table;
   args.rev = rev;
   SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_revision_proplist, &args,
-                                 FALSE, pool));
+                                 FALSE, result_pool));
 
-  *table_p = table ? table : apr_hash_make(pool);
+  *table_p = table ? table : apr_hash_make(result_pool);
   return SVN_NO_ERROR;
 }
 
@@ -216,7 +218,9 @@ svn_fs_base__revision_prop(svn_string_t
                            svn_fs_t *fs,
                            svn_revnum_t rev,
                            const char *propname,
-                           apr_pool_t *pool)
+                           svn_boolean_t refresh,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
 {
   struct revision_proplist_args args;
   apr_hash_t *table;
@@ -227,7 +231,7 @@ svn_fs_base__revision_prop(svn_string_t
   args.table_p = &table;
   args.rev = rev;
   SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_revision_proplist, &args,
-                                 FALSE, pool));
+                                 FALSE, result_pool));
 
   /* And then the prop from that list (if there was a list). */
   *value_p = svn_hash_gets(table, propname);
@@ -247,8 +251,10 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
 {
   transaction_t *txn;
   const char *txn_id;
+  const svn_string_t *present_value;
 
   SVN_ERR(get_rev_txn(&txn, &txn_id, fs, rev, trail, pool));
+  present_value = svn_hash_gets(txn->proplist, name);
 
   /* If there's no proplist, but we're just deleting a property, exit now. */
   if ((! txn->proplist) && (! value))
@@ -262,7 +268,6 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
   if (old_value_p)
     {
       const svn_string_t *wanted_value = *old_value_p;
-      const svn_string_t *present_value = svn_hash_gets(txn->proplist, name);
       if ((!wanted_value != !present_value)
           || (wanted_value && present_value
               && !svn_string_compare(wanted_value, present_value)))
@@ -275,6 +280,13 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
         }
       /* Fall through. */
     }
+
+  /* If the prop-set is a no-op, skip the actual write. */
+  if ((!present_value && !value)
+      || (present_value && value
+          && svn_string_compare(present_value, value)))
+    return SVN_NO_ERROR;
+
   svn_hash_sets(txn->proplist, name, value);
 
   /* Overwrite the revision. */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h Mon Nov 30 10:24:16 2015
@@ -172,12 +172,16 @@ svn_error_t *svn_fs_base__youngest_rev(s
 svn_error_t *svn_fs_base__revision_prop(svn_string_t **value_p, svn_fs_t *fs,
                                         svn_revnum_t rev,
                                         const char *propname,
-                                        apr_pool_t *pool);
+                                        svn_boolean_t refresh,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool);
 
 svn_error_t *svn_fs_base__revision_proplist(apr_hash_t **table_p,
                                             svn_fs_t *fs,
                                             svn_revnum_t rev,
-                                            apr_pool_t *pool);
+                                            svn_boolean_t refresh,
+                                            apr_pool_t *result_pool,
+                                            apr_pool_t *scratch_pool);
 
 svn_error_t *svn_fs_base__change_rev_prop(svn_fs_t *fs, svn_revnum_t rev,
                                           const char *name,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c Mon Nov 30 10:24:16 2015
@@ -68,6 +68,7 @@
 #include "private/svn_fspath.h"
 #include "private/svn_fs_util.h"
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_sorts_private.h"
 
 
 /* ### I believe this constant will become internal to reps-strings.c.
@@ -1285,6 +1286,21 @@ base_node_proplist(apr_hash_t **table_p,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+base_node_has_props(svn_boolean_t *has_props,
+                    svn_fs_root_t *root,
+                    const char *path,
+                    apr_pool_t *scratch_pool)
+{
+  apr_hash_t *props;
+
+  SVN_ERR(base_node_proplist(&props, root, path, scratch_pool));
+
+  *has_props = (0 < apr_hash_count(props));
+
+  return SVN_NO_ERROR;
+}
+
 
 struct change_node_prop_args {
   svn_fs_root_t *root;
@@ -1608,13 +1624,15 @@ static svn_error_t *
 base_dir_optimal_order(apr_array_header_t **ordered_p,
                        svn_fs_root_t *root,
                        apr_hash_t *entries,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
   /* 1:1 copy of entries with no differnce in ordering */
   apr_hash_index_t *hi;
-  apr_array_header_t *result = apr_array_make(pool, apr_hash_count(entries),
-                                              sizeof(svn_fs_dirent_t *));
-  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+  apr_array_header_t *result
+    = apr_array_make(result_pool, apr_hash_count(entries),
+                     sizeof(svn_fs_dirent_t *));
+  for (hi = apr_hash_first(scratch_pool, entries); hi; hi = apr_hash_next(hi))
     APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = apr_hash_this_val(hi);
 
   *ordered_p = result;
@@ -2563,8 +2581,7 @@ verify_locks(const char *txn_name,
       apr_hash_this(hi, &key, NULL, NULL);
       APR_ARRAY_PUSH(changed_paths, const char *) = key;
     }
-  qsort(changed_paths->elts, changed_paths->nelts,
-        changed_paths->elt_size, svn_sort_compare_paths);
+  svn_sort__array(changed_paths, svn_sort_compare_paths);
 
   /* Now, traverse the array of changed paths, verify locks.  Note
      that if we need to do a recursive verification a path, we'll skip
@@ -3164,7 +3181,8 @@ txn_body_copy(void *baton,
   if ((to_parent_path->node)
       && (svn_fs_base__id_compare(svn_fs_base__dag_get_id(from_node),
                                   svn_fs_base__dag_get_id
-                                  (to_parent_path->node)) == svn_fs_node_same))
+                                  (to_parent_path->node))
+          == svn_fs_node_unchanged))
     return SVN_NO_ERROR;
 
   if (! from_root->is_txn_root)
@@ -5489,6 +5507,7 @@ static root_vtable_t root_vtable = {
   base_closest_copy,
   base_node_prop,
   base_node_proplist,
+  base_node_has_props,
   base_change_node_prop,
   base_props_changed,
   base_dir_entries,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c Mon Nov 30 10:24:16 2015
@@ -57,7 +57,7 @@ block_read(void **result,
            apr_pool_t *scratch_pool);
 
 
-/* Defined this to enable access logging via dgb__log_access
+/* Define this to enable access logging via dbg_log_access
 #define SVN_FS_FS__LOG_ACCESS
  */
 
@@ -91,7 +91,7 @@ dbg_log_access(svn_fs_t *fs,
   svn_fs_fs__revision_file_t *rev_file;
 
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision,
-                                           scratch_pool));
+                                           scratch_pool, scratch_pool));
 
   /* determine rev / pack file offset */
   SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, revision, NULL,
@@ -158,7 +158,8 @@ dbg_log_access(svn_fs_t *fs,
     {
       /* reverse index lookup: get item description in ENTRY */
       SVN_ERR(svn_fs_fs__p2l_entry_lookup(&entry, fs, rev_file, revision,
-                                          offset, scratch_pool));
+                                          offset, scratch_pool,
+                                          scratch_pool));
       if (entry)
         {
           /* more details */
@@ -183,6 +184,10 @@ dbg_log_access(svn_fs_t *fs,
              description);
     }
 
+  /* We don't know when SCRATCH_POOL will be cleared, so close the rev file
+     explicitly. */
+  SVN_ERR(svn_fs_fs__close_revision_file(rev_file));
+
 #endif
 
   return SVN_NO_ERROR;
@@ -286,6 +291,114 @@ use_block_read(svn_fs_t *fs)
   return svn_fs_fs__use_log_addressing(fs) && ffd->use_block_read;
 }
 
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+                               representation_t *rep,
+                               apr_pool_t *scratch_pool)
+{
+  svn_checksum_t checksum;
+  svn_checksum_t *empty_md5;
+  svn_fs_fs__revision_file_t *revision_file;
+  svn_fs_fs__rep_header_t *rep_header;
+
+  /* Anything to do at all?
+   *
+   * Note that a 0 SIZE is only possible for PLAIN reps due to the SVN\1
+   * magic prefix in any DELTA rep. */
+  if (!rep || rep->expanded_size != 0 || rep->size == 0)
+    return SVN_NO_ERROR;
+
+  /* This function may only be called for committed data. */
+  assert(!svn_fs_fs__id_txn_used(&rep->txn_id));
+
+  /* EXPANDED_SIZE is 0. If the MD5 does not match the one for empty
+   * contents, we know that EXPANDED_SIZE == 0 is wrong and needs to
+   * be set to the actual value given by SIZE.
+   *
+   * Using svn_checksum_match() will also accept all-zero values for
+   * the MD5 digest and only report a mismatch if the MD5 has actually
+   * been given. */
+  empty_md5 = svn_checksum_empty_checksum(svn_checksum_md5, scratch_pool);
+
+  checksum.digest = rep->md5_digest;
+  checksum.kind = svn_checksum_md5;
+  if (!svn_checksum_match(empty_md5, &checksum))
+    {
+      rep->expanded_size = rep->size;
+      return SVN_NO_ERROR;
+    }
+
+  /* Data in the rep-cache.db does not have MD5 checksums (all zero) on it.
+   * Compare SHA1 instead. */
+  if (rep->has_sha1)
+    {
+      svn_checksum_t *empty_sha1
+        = svn_checksum_empty_checksum(svn_checksum_sha1, scratch_pool);
+
+      checksum.digest = rep->sha1_digest;
+      checksum.kind = svn_checksum_sha1;
+      if (!svn_checksum_match(empty_sha1, &checksum))
+        {
+          rep->expanded_size = rep->size;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  /* Only two cases are left here.
+   * (1) A non-empty PLAIN rep with a MD5 collision on EMPTY_MD5.
+   * (2) A DELTA rep with zero-length output. */
+
+  /* SVN always stores a DELTA rep with zero-length output as an empty
+   * sequence of txdelta windows, i.e. as "SVN\1".  In that case, SIZE is
+   * 4 bytes.  There is no other possible DELTA rep of that size and any
+   * PLAIN rep of 4 bytes would produce a different MD5.  Hence, if SIZE is
+   * actually 4 here, we know that this is an empty DELTA rep.
+   *
+   * Note that it is technically legal to have DELTA reps with a 0 length
+   * output window.  Their on-disk size would be longer.  We handle that
+   * case later together with the equally unlikely MD5 collision. */
+  if (rep->size == 4)
+    {
+      /* EXPANDED_SIZE is already 0. */
+      return SVN_NO_ERROR;
+    }
+
+  /* We still have the two options, PLAIN or DELTA rep.  At this point, we
+   * are in an extremely unlikely case and can spend some time to figure it
+   * out.  So, let's just look at the representation header. */
+  SVN_ERR(open_and_seek_revision(&revision_file, fs, rep->revision,
+                                 rep->item_index, scratch_pool));
+  SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, revision_file->stream,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+
+  /* Only for PLAIN reps do we have to correct EXPANDED_SIZE. */
+  if (rep_header->type == svn_fs_fs__rep_plain)
+    rep->expanded_size = rep->size;
+
+  return SVN_NO_ERROR;
+}
+
+/* Correct known issues with committed NODEREV in FS.
+ * Uses SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+fixup_node_revision(svn_fs_t *fs,
+                    node_revision_t *noderev,
+                    apr_pool_t *scratch_pool)
+{
+  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+  noderev->is_fresh_txn_root = FALSE;
+
+  /* Make sure EXPANDED_SIZE has the correct value for every rep. */
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->data_rep,
+                                         scratch_pool));
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->prop_rep,
+                                         scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Get the node-revision for the node ID in FS.
    Set *NODEREV_P to the new node-revision structure, allocated in POOL.
    See svn_fs_fs__get_node_revision, which wraps this and adds another
@@ -312,14 +425,13 @@ get_node_revision_body(node_revision_t *
                              scratch_pool),
                              APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
                              scratch_pool);
-      if (err)
+      if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+        {
+          svn_error_clear(err);
+          return svn_error_trace(err_dangling_id(fs, id));
+        }
+      else if (err)
         {
-          if (APR_STATUS_IS_ENOENT(err->apr_err))
-            {
-              svn_error_clear(err);
-              return svn_error_trace(err_dangling_id(fs, id));
-            }
-
           return svn_error_trace(err);
         }
 
@@ -376,9 +488,7 @@ get_node_revision_body(node_revision_t *
                                           revision_file->stream,
                                           result_pool,
                                           scratch_pool));
-
-          /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-          (*noderev_p)->is_fresh_txn_root = FALSE;
+          SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
 
           /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
           if (ffd->node_revision_cache)
@@ -765,9 +875,7 @@ create_rep_state_body(rep_state_t **rep_
      Since we don't know the depth of the delta chain, let's assume, the
      whole contents get rewritten 3 times.
    */
-  estimated_window_storage
-    = 4 * (  (rep->expanded_size ? rep->expanded_size : rep->size)
-           + SVN_DELTA_WINDOW_SIZE);
+  estimated_window_storage = 4 * (rep->expanded_size + SVN_DELTA_WINDOW_SIZE);
   estimated_window_storage = MIN(estimated_window_storage, APR_SIZE_MAX);
 
   rs->window_cache =    ffd->txdelta_window_cache
@@ -952,7 +1060,7 @@ svn_fs_fs__check_rep(representation_t *r
       if (   entry == NULL
           || entry->type < SVN_FS_FS__ITEM_TYPE_FILE_REP
           || entry->type > SVN_FS_FS__ITEM_TYPE_DIR_PROPS)
-        return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("No representation found at offset %s "
                                    "for item %s in revision %ld"),
                                  apr_off_t_toa(scratch_pool, offset),
@@ -1322,15 +1430,11 @@ set_cached_combined_window(svn_stringbuf
    ID, and representation REP.
    Also, set *WINDOW_P to the base window content for *LIST, if it
    could be found in cache. Otherwise, *LIST will contain the base
-   representation for the whole delta chain.
-   Finally, return the expanded size of the representation in
-   *EXPANDED_SIZE. It will take care of cases where only the on-disk
-   size is known.  */
+   representation for the whole delta chain. */
 static svn_error_t *
 build_rep_list(apr_array_header_t **list,
                svn_stringbuf_t **window_p,
                rep_state_t **src_state,
-               svn_filesize_t *expanded_size,
                svn_fs_t *fs,
                representation_t *first_rep,
                apr_pool_t *pool)
@@ -1345,24 +1449,9 @@ build_rep_list(apr_array_header_t **list
   *list = apr_array_make(pool, 1, sizeof(rep_state_t *));
   rep = *first_rep;
 
-  /* The value as stored in the data struct.
-     0 is either for unknown length or actually zero length. */
-  *expanded_size = first_rep->expanded_size;
-
   /* for the top-level rep, we need the rep_args */
   SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file, &rep, fs, pool,
                            iterpool));
-
-  /* Unknown size or empty representation?
-     That implies the this being the first iteration.
-     Usually size equals on-disk size, except for empty,
-     compressed representations (delta, size = 4).
-     Please note that for all non-empty deltas have
-     a 4-byte header _plus_ some data. */
-  if (*expanded_size == 0)
-    if (rep_header->type == svn_fs_fs__rep_plain || first_rep->size != 4)
-      *expanded_size = first_rep->size;
-
   while (1)
     {
       svn_pool_clear(iterpool);
@@ -1624,9 +1713,11 @@ get_combined_window(svn_stringbuf_t **re
       /* Maybe, we've got a PLAIN start representation.  If we do, read
          as much data from it as the needed for the txdelta window's source
          view.
-         Note that BUF / SOURCE may only be NULL in the first iteration. */
+         Note that BUF / SOURCE may only be NULL in the first iteration.
+         Also note that we may have short-cut reading the delta chain --
+         in which case SRC_OPS is 0 and it might not be a PLAIN rep. */
       source = buf;
-      if (source == NULL && rb->src_state != NULL)
+      if (source == NULL && rb->src_state != NULL && window->src_ops)
         SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
                                   pool, iterpool));
 
@@ -1664,7 +1755,7 @@ get_combined_window(svn_stringbuf_t **re
 }
 
 /* Returns whether or not the expanded fulltext of the file is cachable
- * based on its size SIZE.  The decision depends on the cache used by RB.
+ * based on its size SIZE.  The decision depends on the cache used by FFD.
  */
 static svn_boolean_t
 fulltext_size_is_cachable(fs_fs_data_t *ffd, svn_filesize_t size)
@@ -1997,8 +2088,9 @@ rep_read_contents(void *baton,
   if (!rb->rs_list)
     {
       /* Window stream not initialized, yet.  Do it now. */
+      rb->len = rb->rep.expanded_size;
       SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window,
-                             &rb->src_state, &rb->len, rb->fs, &rb->rep,
+                             &rb->src_state, rb->fs, &rb->rep,
                              rb->filehandle_pool));
 
       /* In case we did read from the fulltext cache before, make the
@@ -2065,7 +2157,6 @@ svn_fs_fs__get_contents(svn_stream_t **c
   else
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
       struct rep_read_baton *rb;
 
       pair_cache_key_t fulltext_cache_key = { 0 };
@@ -2081,7 +2172,7 @@ svn_fs_fs__get_contents(svn_stream_t **c
        * cache it. */
       if (ffd->fulltext_cache && cache_fulltext
           && SVN_IS_VALID_REVNUM(rep->revision)
-          && fulltext_size_is_cachable(ffd, len))
+          && fulltext_size_is_cachable(ffd, rep->expanded_size))
         {
           rb->fulltext_cache = ffd->fulltext_cache;
         }
@@ -2330,12 +2421,12 @@ compare_dirent_name(const void *a, const
   return strcmp(lhs->name, rhs);
 }
 
-/* Into ENTRIES, read all directories entries from the key-value text in
+/* Into *ENTRIES_P, read all directories entries from the key-value text in
  * STREAM.  If INCREMENTAL is TRUE, read until the end of the STREAM and
  * update the data.  ID is provided for nicer error messages.
  */
 static svn_error_t *
-read_dir_entries(apr_array_header_t *entries,
+read_dir_entries(apr_array_header_t **entries_p,
                  svn_stream_t *stream,
                  svn_boolean_t incremental,
                  const svn_fs_id_t *id,
@@ -2343,8 +2434,14 @@ read_dir_entries(apr_array_header_t *ent
                  apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  apr_hash_t *hash = incremental ? svn_hash__make(scratch_pool) : NULL;
+  apr_hash_t *hash = NULL;
   const char *terminator = SVN_HASH_TERMINATOR;
+  apr_array_header_t *entries = NULL;
+
+  if (incremental)
+    hash = svn_hash__make(scratch_pool);
+  else
+    entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
 
   /* Read until the terminator (non-incremental) or the end of STREAM
      (incremental mode).  In the latter mode, we use a temporary HASH
@@ -2425,6 +2522,9 @@ read_dir_entries(apr_array_header_t *ent
   if (incremental)
     {
       apr_hash_index_t *hi;
+
+      entries = apr_array_make(result_pool, apr_hash_count(hash),
+                               sizeof(svn_fs_dirent_t *));
       for (hi = apr_hash_first(iterpool, hash); hi; hi = apr_hash_next(hi))
         APR_ARRAY_PUSH(entries, svn_fs_dirent_t *) = apr_hash_this_val(hi);
     }
@@ -2434,14 +2534,45 @@ read_dir_entries(apr_array_header_t *ent
 
   svn_pool_destroy(iterpool);
 
+  *entries_p = entries;
   return SVN_NO_ERROR;
 }
 
-/* Fetch the contents of a directory into ENTRIES.  Values are stored
+/* For directory NODEREV in FS, return the *FILESIZE of its in-txn
+ * representation.  If the directory representation is comitted data,
+ * set *FILESIZE to SVN_INVALID_FILESIZE. Use SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+get_txn_dir_info(svn_filesize_t *filesize,
+                 svn_fs_t *fs,
+                 node_revision_t *noderev,
+                 apr_pool_t *scratch_pool)
+{
+  if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
+    {
+      const svn_io_dirent2_t *dirent;
+      const char *filename;
+
+      filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+                                                   scratch_pool);
+
+      SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+                                  scratch_pool, scratch_pool));
+      *filesize = dirent->filesize;
+    }
+  else
+    {
+      *filesize = SVN_INVALID_FILESIZE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Fetch the contents of a directory into DIR.  Values are stored
    as filename to string mappings; further conversion is necessary to
    convert them into svn_fs_dirent_t values. */
 static svn_error_t *
-get_dir_contents(apr_array_header_t **entries,
+get_dir_contents(svn_fs_fs__dir_data_t *dir,
                  svn_fs_t *fs,
                  node_revision_t *noderev,
                  apr_pool_t *result_pool,
@@ -2449,18 +2580,30 @@ get_dir_contents(apr_array_header_t **en
 {
   svn_stream_t *contents;
 
-  *entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
+  /* Initialize the result. */
+  dir->txn_filesize = SVN_INVALID_FILESIZE;
+
+  /* Read dir contents - unless there is none in which case we are done. */
   if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
     {
-      const char *filename
-        = svn_fs_fs__path_txn_node_children(fs, noderev->id, scratch_pool);
+      /* Get location & current size of the directory representation. */
+      const char *filename;
+      apr_file_t *file;
+
+      filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+                                                   scratch_pool);
 
       /* The representation is mutable.  Read the old directory
          contents from the mutable children file, followed by the
          changes we've made in this transaction. */
-      SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool,
-                                       scratch_pool));
-      SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id,
+      SVN_ERR(svn_io_file_open(&file, filename, APR_READ | APR_BUFFERED,
+                               APR_OS_DEFAULT, scratch_pool));
+
+      /* Obtain txn children file size. */
+      SVN_ERR(svn_io_file_size_get(&dir->txn_filesize, file, scratch_pool));
+
+      contents = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+      SVN_ERR(read_dir_entries(&dir->entries, contents, TRUE, noderev->id,
                                result_pool, scratch_pool));
       SVN_ERR(svn_stream_close(contents));
     }
@@ -2469,9 +2612,7 @@ get_dir_contents(apr_array_header_t **en
       /* Undeltify content before parsing it. Otherwise, we could only
        * parse it byte-by-byte.
        */
-      apr_size_t len = noderev->data_rep->expanded_size
-                     ? (apr_size_t)noderev->data_rep->expanded_size
-                     : (apr_size_t)noderev->data_rep->size;
+      apr_size_t len = noderev->data_rep->expanded_size;
       svn_stringbuf_t *text;
 
       /* The representation is immutable.  Read it normally. */
@@ -2482,9 +2623,13 @@ get_dir_contents(apr_array_header_t **en
 
       /* de-serialize hash */
       contents = svn_stream_from_stringbuf(text, scratch_pool);
-      SVN_ERR(read_dir_entries(*entries, contents, FALSE,  noderev->id,
+      SVN_ERR(read_dir_entries(&dir->entries, contents, FALSE, noderev->id,
                                result_pool, scratch_pool));
     }
+  else
+    {
+       dir->entries = apr_array_make(result_pool, 0, sizeof(svn_fs_dirent_t *));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2503,27 +2648,27 @@ locate_dir_cache(svn_fs_t *fs,
                  apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  if (svn_fs_fs__id_is_txn(noderev->id))
+  if (!noderev->data_rep)
+    {
+      /* no data rep -> empty directory.
+         A NULL key causes a cache miss. */
+      *key = NULL;
+      return ffd->dir_cache;
+    }
+
+  if (svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
     {
       /* data in txns requires the expensive fs_id-based addressing mode */
       *key = svn_fs_fs__id_unparse(noderev->id, pool)->data;
+
       return ffd->txn_dir_cache;
     }
   else
     {
       /* committed data can use simple rev,item pairs */
-      if (noderev->data_rep)
-        {
-          pair_key->revision = noderev->data_rep->revision;
-          pair_key->second = noderev->data_rep->item_index;
-          *key = pair_key;
-        }
-      else
-        {
-          /* no data rep -> empty directory.
-             A NULL key causes a cache miss. */
-          *key = NULL;
-        }
+      pair_key->revision = noderev->data_rep->revision;
+      pair_key->second = noderev->data_rep->item_index;
+      *key = pair_key;
 
       return ffd->dir_cache;
     }
@@ -2538,6 +2683,7 @@ svn_fs_fs__rep_contents_dir(apr_array_he
 {
   pair_cache_key_t pair_key = { 0 };
   const void *key;
+  svn_fs_fs__dir_data_t *dir;
 
   /* find the cache we may use */
   svn_cache__t *cache = locate_dir_cache(fs, &key, &pair_key, noderev,
@@ -2546,19 +2692,32 @@ svn_fs_fs__rep_contents_dir(apr_array_he
     {
       svn_boolean_t found;
 
-      SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, key,
+      SVN_ERR(svn_cache__get((void **)&dir, &found, cache, key,
                              result_pool));
       if (found)
-        return SVN_NO_ERROR;
+        {
+          /* Verify that the cached dir info is not stale
+           * (no-op for committed data). */
+          svn_filesize_t filesize;
+          SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
+          if (filesize == dir->txn_filesize)
+            {
+              /* Still valid. Done. */
+              *entries_p = dir->entries;
+              return SVN_NO_ERROR;
+            }
+        }
     }
 
   /* Read in the directory contents. */
-  SVN_ERR(get_dir_contents(entries_p, fs, noderev, result_pool,
-                           scratch_pool));
+  dir = apr_pcalloc(scratch_pool, sizeof(*dir));
+  SVN_ERR(get_dir_contents(dir, fs, noderev, result_pool, scratch_pool));
+  *entries_p = dir->entries;
 
   /* Update the cache, if we are to use one. */
   if (cache)
-    SVN_ERR(svn_cache__set(cache, key, *entries_p, scratch_pool));
+    SVN_ERR(svn_cache__set(cache, key, dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2590,30 +2749,40 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
                                          scratch_pool);
   if (cache)
     {
+      extract_dir_entry_baton_t baton;
+
+      svn_filesize_t filesize;
+      SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
       /* Cache lookup. */
+      baton.txn_filesize = filesize;
+      baton.name = name;
       SVN_ERR(svn_cache__get_partial((void **)dirent,
                                      &found,
                                      cache,
                                      key,
                                      svn_fs_fs__extract_dir_entry,
-                                     (void*)name,
+                                     &baton,
                                      result_pool));
     }
 
   /* fetch data from disk if we did not find it in the cache */
   if (! found)
     {
-      apr_array_header_t *entries;
       svn_fs_dirent_t *entry;
       svn_fs_dirent_t *entry_copy = NULL;
+      svn_fs_fs__dir_data_t dir;
 
-      /* read the dir from the file system. It will probably be put it
-         into the cache for faster lookup in future calls. */
-      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev,
-                                          scratch_pool, scratch_pool));
+      /* Read in the directory contents. */
+      SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool,
+                               scratch_pool));
+
+      /* Update the cache, if we are to use one. */
+      if (cache)
+        SVN_ERR(svn_cache__set(cache, key, &dir, scratch_pool));
 
       /* find desired entry and return a copy in POOL, if found */
-      entry = svn_fs_fs__find_dir_entry(entries, name, NULL);
+      entry = svn_fs_fs__find_dir_entry(dir.entries, name, NULL);
       if (entry)
         {
           entry_copy = apr_palloc(result_pool, sizeof(*entry_copy));
@@ -2639,16 +2808,27 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
 
   if (noderev->prop_rep && svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
     {
+      svn_error_t *err;
       const char *filename
         = svn_fs_fs__path_txn_node_props(fs, noderev->id, pool);
       proplist = apr_hash_make(pool);
 
       SVN_ERR(svn_stream_open_readonly(&stream, filename, pool, pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+      err = svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool);
+      if (err)
+        {
+          svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+          err = svn_error_compose_create(err, svn_stream_close(stream));
+          return svn_error_quick_wrapf(err,
+                   _("malformed property list for node-revision '%s' in '%s'"),
+                   id_str->data, filename);
+        }
       SVN_ERR(svn_stream_close(stream));
     }
   else if (noderev->prop_rep)
     {
+      svn_error_t *err;
       fs_fs_data_t *ffd = fs->fsap_data;
       representation_t *rep = noderev->prop_rep;
       pair_cache_key_t key = { 0 };
@@ -2667,7 +2847,16 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
       proplist = apr_hash_make(pool);
       SVN_ERR(svn_fs_fs__get_contents(&stream, fs, noderev->prop_rep, FALSE,
                                       pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+      err = svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool);
+      if (err)
+        {
+          svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+          err = svn_error_compose_create(err, svn_stream_close(stream));
+          return svn_error_quick_wrapf(err,
+                   _("malformed property list for node-revision '%s'"),
+                   id_str->data);
+        }
       SVN_ERR(svn_stream_close(stream));
 
       if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
@@ -2690,7 +2879,7 @@ svn_fs_fs__get_changes(apr_array_header_
                        svn_revnum_t rev,
                        apr_pool_t *result_pool)
 {
-  apr_off_t changes_offset = SVN_FS_FS__ITEM_INDEX_CHANGES;
+  apr_off_t item_index = SVN_FS_FS__ITEM_INDEX_CHANGES;
   svn_fs_fs__revision_file_t *revision_file;
   svn_boolean_t found;
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -2725,17 +2914,26 @@ svn_fs_fs__get_changes(apr_array_header_
         }
       else
         {
+          apr_off_t changes_offset;
+
           /* Addressing is very different for old formats
            * (needs to read the revision trailer). */
           if (svn_fs_fs__use_log_addressing(fs))
-            SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs,
-                                           revision_file, rev, NULL,
-                                           SVN_FS_FS__ITEM_INDEX_CHANGES,
-                                           scratch_pool));
+            {
+              SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs,
+                                             revision_file, rev, NULL,
+                                             SVN_FS_FS__ITEM_INDEX_CHANGES,
+                                             scratch_pool));
+            }
           else
-            SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
-                                            revision_file, fs, rev,
-                                            scratch_pool));
+            {
+              SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
+                                              revision_file, fs, rev,
+                                              scratch_pool));
+
+              /* This variable will be used for debug logging only. */
+              item_index = changes_offset;
+            }
 
           /* Actual reading and parsing are the same, though. */
           SVN_ERR(aligned_seek(fs, revision_file->file, NULL, changes_offset,
@@ -2763,7 +2961,7 @@ svn_fs_fs__get_changes(apr_array_header_
       SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
     }
 
-  SVN_ERR(dbg_log_access(fs, rev, changes_offset, *changes,
+  SVN_ERR(dbg_log_access(fs, rev, item_index, *changes,
                          SVN_FS_FS__ITEM_TYPE_CHANGES, scratch_pool));
 
   svn_pool_destroy(scratch_pool);
@@ -3200,9 +3398,7 @@ block_read_noderev(node_revision_t **nod
   /* read node rev from revision file */
   SVN_ERR(svn_fs_fs__read_noderev(noderev_p, stream,
                                   result_pool, scratch_pool));
-
-  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-  (*noderev_p)->is_fresh_txn_root = FALSE;
+  SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
 
   if (ffd->node_revision_cache)
     SVN_ERR(svn_cache__set(ffd->node_revision_cache, &key, *noderev_p,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h Mon Nov 30 10:24:16 2015
@@ -30,6 +30,18 @@
 
 
 
+/* Resolve a FSFS quirk: if REP in FS is a "PLAIN" representation, its
+ * EXPANDED_SIZE element may be 0, in which case its value has to be taken
+ * from SIZE.
+ *
+ * This function ensures that EXPANDED_SIZE in REP always contains the
+ * actual value. No-op if REP is NULL.  Uses SCRATCH_POOL for temporaries.
+ */
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+                               representation_t *rep,
+                               apr_pool_t *scratch_pool);
+
 /* Set *NODEREV_P to the node-revision for the node ID in FS.  Do any
    allocations in POOL. */
 svn_error_t *

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c Mon Nov 30 10:24:16 2015
@@ -274,7 +274,8 @@ init_callbacks(svn_cache__t *cache,
  * MEMBUFFER is not NULL. Fallbacks to inprocess cache if MEMCACHE and
  * MEMBUFFER are NULL and pages is non-zero.  Sets *CACHE_P to NULL
  * otherwise.  Use the given PRIORITY class for the new cache.  If it
- * is 0, then use the default priority class.
+ * is 0, then use the default priority class.  HAS_NAMESPACE indicates
+ * whether we prefixed this cache instance with a namespace.
  *
  * Unless NO_HANDLER is true, register an error handler that reports errors
  * as warnings to the FS warning callback.
@@ -292,6 +293,7 @@ create_cache(svn_cache__t **cache_p,
              apr_ssize_t klen,
              const char *prefix,
              apr_uint32_t priority,
+             svn_boolean_t has_namespace,
              svn_fs_t *fs,
              svn_boolean_t no_handler,
              apr_pool_t *result_pool,
@@ -314,9 +316,12 @@ create_cache(svn_cache__t **cache_p,
     }
   else if (membuffer)
     {
+      /* We assume caches with namespaces to be relatively short-lived,
+       * i.e. their data will not be needed after a while. */
       SVN_ERR(svn_cache__create_membuffer_cache(
                 cache_p, membuffer, serializer, deserializer,
-                klen, prefix, priority, FALSE, result_pool, scratch_pool));
+                klen, prefix, priority, FALSE, has_namespace,
+                result_pool, scratch_pool));
     }
   else if (pages)
     {
@@ -349,6 +354,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   svn_boolean_t cache_txdeltas;
   svn_boolean_t cache_fulltexts;
   const char *cache_namespace;
+  svn_boolean_t has_namespace;
 
   /* Evaluating the cache configuration. */
   SVN_ERR(read_config(&cache_namespace,
@@ -358,6 +364,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                       pool));
 
   prefix = apr_pstrcat(pool, "ns:", cache_namespace, ":", prefix, SVN_VA_NULL);
+  has_namespace = strlen(cache_namespace) > 0;
 
   membuffer = svn_cache__get_global_membuffer_cache();
 
@@ -386,34 +393,35 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
    * commands, this is only going to contain a few entries (svnadmin
    * dump/verify is an exception here), so to reduce overhead let's
    * try to keep it to just one page.  I estimate each entry has about
-   * 72 bytes of overhead (svn_revnum_t key, svn_fs_id_t +
-   * id_private_t + 3 strings for value, and the cache_entry); the
-   * default pool size is 8192, so about a hundred should fit
-   * comfortably. */
+   * 130 bytes of overhead (svn_revnum_t key, ID struct, and the cache_entry);
+   * the default pool size is 8192, so about a fifty should fit comfortably.
+   */
   SVN_ERR(create_cache(&(ffd->rev_root_id_cache),
                        NULL,
                        membuffer,
-                       1, 100,
+                       1, 50,
                        svn_fs_fs__serialize_id,
                        svn_fs_fs__deserialize_id,
                        sizeof(svn_revnum_t),
                        apr_pstrcat(pool, prefix, "RRI", SVN_VA_NULL),
                        0,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
 
-  /* Rough estimate: revision DAG nodes have size around 320 bytes, so
-   * let's put 16 on a page. */
+  /* Rough estimate: revision DAG nodes have size around 1kBytes, so
+   * let's put 8 on a page. */
   SVN_ERR(create_cache(&(ffd->rev_node_cache),
                        NULL,
                        membuffer,
-                       1024, 16,
+                       1, 8,
                        svn_fs_fs__dag_serialize,
                        svn_fs_fs__dag_deserialize,
                        APR_HASH_KEY_STRING,
                        apr_pstrcat(pool, prefix, "DAG", SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -425,28 +433,30 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   SVN_ERR(create_cache(&(ffd->dir_cache),
                        NULL,
                        membuffer,
-                       1024, 8,
+                       1, 8,
                        svn_fs_fs__serialize_dir_entries,
                        svn_fs_fs__deserialize_dir_entries,
                        sizeof(pair_cache_key_t),
                        apr_pstrcat(pool, prefix, "DIR", SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
 
-  /* Only 16 bytes per entry (a revision number + the corresponding offset).
-     Since we want ~8k pages, that means 512 entries per page. */
+  /* 8 kBytes per entry (1000 revs / shared, one file offset per rev).
+     Covering about 8 pack files gives us an "o.k." hit rate. */
   SVN_ERR(create_cache(&(ffd->packed_offset_cache),
                        NULL,
                        membuffer,
-                       32, 1,
+                       8, 1,
                        svn_fs_fs__serialize_manifest,
                        svn_fs_fs__deserialize_manifest,
                        sizeof(svn_revnum_t),
                        apr_pstrcat(pool, prefix, "PACK-MANIFEST",
                                    SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -455,12 +465,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   SVN_ERR(create_cache(&(ffd->node_revision_cache),
                        NULL,
                        membuffer,
-                       32, 32, /* ~200 byte / entry; 1k entries total */
+                       2, 16, /* ~500 byte / entry; 32 entries total */
                        svn_fs_fs__serialize_node_revision,
                        svn_fs_fs__deserialize_node_revision,
                        sizeof(pair_cache_key_t),
                        apr_pstrcat(pool, prefix, "NODEREVS", SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -469,12 +480,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   SVN_ERR(create_cache(&(ffd->rep_header_cache),
                        NULL,
                        membuffer,
-                       1, 1000, /* ~8 bytes / entry; 1k entries total */
+                       1, 200, /* ~40 bytes / entry; 200 entries total */
                        svn_fs_fs__serialize_rep_header,
                        svn_fs_fs__deserialize_rep_header,
                        sizeof(pair_cache_key_t),
                        apr_pstrcat(pool, prefix, "REPHEADER", SVN_VA_NULL),
                        SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -489,6 +501,22 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        sizeof(svn_revnum_t),
                        apr_pstrcat(pool, prefix, "CHANGES", SVN_VA_NULL),
                        0,
+                       has_namespace,
+                       fs,
+                       no_handler,
+                       fs->pool, pool));
+
+  /* if enabled, cache revprops */
+  SVN_ERR(create_cache(&(ffd->revprop_cache),
+                       NULL,
+                       membuffer,
+                       0, 0, /* Do not use inprocess cache */
+                       svn_fs_fs__serialize_revprops,
+                       svn_fs_fs__deserialize_revprops,
+                       sizeof(pair_cache_key_t),
+                       apr_pstrcat(pool, prefix, "REVPROP", SVN_VA_NULL),
+                       SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                       TRUE, /* contents is short-lived */
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -499,12 +527,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->fulltext_cache),
                            ffd->memcache,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            /* Values are svn_stringbuf_t */
                            NULL, NULL,
                            sizeof(pair_cache_key_t),
                            apr_pstrcat(pool, prefix, "TEXT", SVN_VA_NULL),
                            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -512,13 +541,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->properties_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            svn_fs_fs__serialize_properties,
                            svn_fs_fs__deserialize_properties,
                            sizeof(pair_cache_key_t),
                            apr_pstrcat(pool, prefix, "PROP",
                                        SVN_VA_NULL),
                            SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -526,13 +556,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->mergeinfo_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            svn_fs_fs__serialize_mergeinfo,
                            svn_fs_fs__deserialize_mergeinfo,
                            APR_HASH_KEY_STRING,
                            apr_pstrcat(pool, prefix, "MERGEINFO",
                                        SVN_VA_NULL),
                            0,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -540,13 +571,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->mergeinfo_existence_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            /* Values are svn_stringbuf_t */
                            NULL, NULL,
                            APR_HASH_KEY_STRING,
                            apr_pstrcat(pool, prefix, "HAS_MERGEINFO",
                                        SVN_VA_NULL),
                            0,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -565,13 +597,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->raw_window_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            svn_fs_fs__serialize_raw_window,
                            svn_fs_fs__deserialize_raw_window,
                            sizeof(window_cache_key_t),
                            apr_pstrcat(pool, prefix, "RAW_WINDOW",
                                        SVN_VA_NULL),
                            SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -579,13 +612,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->txdelta_window_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            svn_fs_fs__serialize_txdelta_window,
                            svn_fs_fs__deserialize_txdelta_window,
                            sizeof(window_cache_key_t),
                            apr_pstrcat(pool, prefix, "TXDELTA_WINDOW",
                                        SVN_VA_NULL),
                            SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -593,13 +627,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       SVN_ERR(create_cache(&(ffd->combined_window_cache),
                            NULL,
                            membuffer,
-                           0, 0, /* Do not use inprocess cache */
+                           0, 0, /* Do not use the inprocess cache */
                            /* Values are svn_stringbuf_t */
                            NULL, NULL,
                            sizeof(window_cache_key_t),
                            apr_pstrcat(pool, prefix, "COMBINED_WINDOW",
                                        SVN_VA_NULL),
                            SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+                           has_namespace,
                            fs,
                            no_handler,
                            fs->pool, pool));
@@ -613,28 +648,34 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   SVN_ERR(create_cache(&(ffd->l2p_header_cache),
                        NULL,
                        membuffer,
-                       64, 16, /* entry size varies but we must cover
-                                  a reasonable number of revisions (1k) */
+                       8, 16, /* entry size varies but we must cover a
+                                 reasonable number of rev / pack files
+                                 to allow for delta chains to be walked
+                                 efficiently etc. */
                        svn_fs_fs__serialize_l2p_header,
                        svn_fs_fs__deserialize_l2p_header,
                        sizeof(pair_cache_key_t),
                        apr_pstrcat(pool, prefix, "L2P_HEADER",
                                    (char *)NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
   SVN_ERR(create_cache(&(ffd->l2p_page_cache),
                        NULL,
                        membuffer,
-                       64, 16, /* entry size varies but we must cover
-                                  a reasonable number of revisions (1k) */
+                       8, 16, /* entry size varies but we must cover a
+                                 reasonable number of rev / pack files
+                                 to allow for delta chains to be walked
+                                 efficiently etc. */
                        svn_fs_fs__serialize_l2p_page,
                        svn_fs_fs__deserialize_l2p_page,
                        sizeof(svn_fs_fs__page_cache_key_t),
                        apr_pstrcat(pool, prefix, "L2P_PAGE",
                                    (char *)NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -648,19 +689,21 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        apr_pstrcat(pool, prefix, "P2L_HEADER",
                                    (char *)NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
   SVN_ERR(create_cache(&(ffd->p2l_page_cache),
                        NULL,
                        membuffer,
-                       4, 16, /* Variably sized entries. Rarely used. */
+                       4, 1, /* Variably sized entries. Rarely used. */
                        svn_fs_fs__serialize_p2l_page,
                        svn_fs_fs__deserialize_p2l_page,
                        sizeof(svn_fs_fs__page_cache_key_t),
                        apr_pstrcat(pool, prefix, "P2L_PAGE",
                                    (char *)NULL),
                        SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       has_namespace,
                        fs,
                        no_handler,
                        fs->pool, pool));
@@ -773,18 +816,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
                                  apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* Transaction content needs to be carefully prefixed to virtually
-     eliminate any chance for conflicts. The (repo, txn_id) pair
-     should be unique but if a transaction fails, it might be possible
-     to start a new transaction later that receives the same id.
-     Therefore, throw in a uuid as well - just to be sure. */
-  const char *prefix = apr_pstrcat(pool,
-                                   "fsfs:", fs->uuid,
-                                   "/", fs->path,
-                                   ":", txn_id,
-                                   ":", svn_uuid_generate(pool), ":",
-                                   SVN_VA_NULL);
+  const char *prefix;
 
   /* We don't support caching for concurrent transactions in the SAME
    * FSFS session. Maybe, you forgot to clean POOL. */
@@ -796,6 +828,19 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
       return SVN_NO_ERROR;
     }
 
+  /* Transaction content needs to be carefully prefixed to virtually
+     eliminate any chance for conflicts. The (repo, txn_id) pair
+     should be unique but if a transaction fails, it might be possible
+     to start a new transaction later that receives the same id.
+     Therefore, throw in a uuid as well - just to be sure. */
+  prefix = apr_pstrcat(pool,
+                       "fsfs:", fs->uuid,
+                       "/", fs->path,
+                       ":", txn_id,
+                       ":", svn_uuid_generate(pool),
+                       ":", "TXNDIR",
+                       SVN_VA_NULL);
+
   /* create a txn-local directory cache */
   SVN_ERR(create_cache(&ffd->txn_dir_cache,
                        NULL,
@@ -804,9 +849,9 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
                        svn_fs_fs__serialize_dir_entries,
                        svn_fs_fs__deserialize_dir_entries,
                        APR_HASH_KEY_STRING,
-                       apr_pstrcat(pool, prefix, "TXNDIR",
-                                   SVN_VA_NULL),
+                       prefix,
                        0,
+                       TRUE, /* The TXN-ID is our namespace. */
                        fs,
                        TRUE,
                        pool, pool));

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c Mon Nov 30 10:24:16 2015
@@ -498,6 +498,40 @@ svn_fs_fs__dag_get_proplist(apr_hash_t *
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+                         dag_node_t *node,
+                         apr_pool_t *scratch_pool)
+{
+  node_revision_t *noderev;
+
+  SVN_ERR(get_node_revision(&noderev, node));
+
+  if (! noderev->prop_rep)
+    {
+      *has_props = FALSE; /* Easy out */
+      return SVN_NO_ERROR;
+    }
+
+  if (svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
+    {
+      /* We are in a commit or something. Check actual properties */
+      apr_hash_t *proplist;
+
+      SVN_ERR(svn_fs_fs__get_proplist(&proplist, node->fs,
+                                      noderev, scratch_pool));
+
+      *has_props = proplist ? (0 < apr_hash_count(proplist)) : FALSE;
+    }
+  else
+    {
+      /* Properties are stored as a standard hash stream,
+         always ending with "END\n" (4 bytes) */
+      *has_props = noderev->prop_rep->expanded_size > 4;
+    }
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_fs_fs__dag_set_proplist(dag_node_t *node,
@@ -1271,34 +1305,58 @@ svn_fs_fs__dag_things_different(svn_bool
                                 apr_pool_t *pool)
 {
   node_revision_t *noderev1, *noderev2;
-  svn_fs_t *fs;
-  svn_boolean_t same;
 
   /* If we have no place to store our results, don't bother doing
      anything. */
   if (! props_changed && ! contents_changed)
     return SVN_NO_ERROR;
 
-  fs = svn_fs_fs__dag_get_fs(node1);
-
   /* The node revision skels for these two nodes. */
   SVN_ERR(get_node_revision(&noderev1, node1));
   SVN_ERR(get_node_revision(&noderev2, node2));
 
-  /* Compare property keys. */
-  if (props_changed != NULL)
+  if (strict)
     {
-      SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, noderev1, noderev2,
-                                        strict, pool));
-      *props_changed = !same;
-    }
+      /* In strict mode, compare text and property representations in the
+         svn_fs_contents_different() / svn_fs_props_different() manner.
 
-  /* Compare contents keys. */
-  if (contents_changed != NULL)
+         See the "No-op changes no longer dumped by 'svnadmin dump' in 1.9"
+         discussion (http://svn.haxx.se/dev/archive-2015-09/0269.shtml) and
+         issue #4598 (https://issues.apache.org/jira/browse/SVN-4598). */
+      svn_fs_t *fs = svn_fs_fs__dag_get_fs(node1);
+      svn_boolean_t same;
+
+      /* Compare property keys. */
+      if (props_changed != NULL)
+        {
+          SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, noderev1,
+                                            noderev2, pool));
+          *props_changed = !same;
+        }
+
+      /* Compare contents keys. */
+      if (contents_changed != NULL)
+        {
+          SVN_ERR(svn_fs_fs__file_text_rep_equal(&same, fs, noderev1,
+                                                 noderev2, pool));
+          *contents_changed = !same;
+        }
+    }
+  else
     {
-      SVN_ERR(svn_fs_fs__file_text_rep_equal(&same, fs, noderev1, noderev2,
-                                             strict, pool));
-      *contents_changed = !same;
+      /* Otherwise, compare representation keys -- as in Subversion 1.8. */
+
+      /* Compare property keys. */
+      if (props_changed != NULL)
+        *props_changed =
+          !svn_fs_fs__noderev_same_rep_key(noderev1->prop_rep,
+                                           noderev2->prop_rep);
+
+      /* Compare contents keys. */
+      if (contents_changed != NULL)
+        *contents_changed =
+          !svn_fs_fs__noderev_same_rep_key(noderev1->data_rep,
+                                           noderev2->data_rep);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h Mon Nov 30 10:24:16 2015
@@ -177,6 +177,12 @@ svn_error_t *svn_fs_fs__dag_get_proplist
                                          dag_node_t *node,
                                          apr_pool_t *pool);
 
+/* Set *HAS_PROPS to TRUE if NODE has properties. Use SCRATCH_POOL
+   for temporary allocations */
+svn_error_t *svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+                                      dag_node_t *node,
+                                      apr_pool_t *scratch_pool);
+
 /* Set the property list of NODE to PROPLIST, allocating from POOL.
    The node being changed must be mutable.
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c Mon Nov 30 10:24:16 2015
@@ -27,7 +27,6 @@
 #include <apr_general.h>
 #include <apr_pools.h>
 #include <apr_file_io.h>
-#include <apr_thread_mutex.h>
 
 #include "svn_fs.h"
 #include "svn_delta.h"
@@ -135,8 +134,29 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__initialize_shared_data(svn_fs_t *fs,
+                                  svn_mutex__t *common_pool_lock,
+                                  apr_pool_t *pool,
+                                  apr_pool_t *common_pool)
+{
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       fs_serialized_init(fs, common_pool, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 
+static svn_error_t *
+fs_refresh_revprops(svn_fs_t *fs,
+                    apr_pool_t *scratch_pool)
+{
+  svn_fs_fs__reset_revprop_cache(fs);
+
+  return SVN_NO_ERROR;
+}
+
 /* This function is provided for Subversion 1.0.x compatibility.  It
    has no effect for fsfs backed Subversion filesystems.  It conforms
    to the fs_library_vtable_t.bdb_set_errcall() API. */
@@ -163,9 +183,11 @@ fs_freeze_body(void *baton,
 
   SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
   if (exists)
-    SVN_ERR(svn_fs_fs__lock_rep_cache(b->fs, pool));
-
-  SVN_ERR(b->freeze_func(b->freeze_baton, pool));
+    SVN_ERR(svn_fs_fs__with_rep_cache_lock(b->fs,
+                                           b->freeze_func, b->freeze_baton,
+                                           pool));
+  else
+    SVN_ERR(b->freeze_func(b->freeze_baton, pool));
 
   return SVN_NO_ERROR;
 }
@@ -236,6 +258,7 @@ fs_set_uuid(svn_fs_t *fs,
 /* The vtable associated with a specific open filesystem. */
 static fs_vtable_t fs_vtable = {
   svn_fs_fs__youngest_rev,
+  fs_refresh_revprops,
   svn_fs_fs__revision_prop,
   svn_fs_fs__get_revision_proplist,
   svn_fs_fs__change_rev_prop,
@@ -268,6 +291,7 @@ initialize_fs_struct(svn_fs_t *fs)
 {
   fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
   ffd->use_log_addressing = FALSE;
+  ffd->revprop_prefix = 0;
 
   fs->vtable = &fs_vtable;
   fs->fsap_data = ffd;
@@ -291,18 +315,18 @@ static svn_error_t *
 fs_create(svn_fs_t *fs,
           const char *path,
           svn_mutex__t *common_pool_lock,
-          apr_pool_t *pool,
+          apr_pool_t *scratch_pool,
           apr_pool_t *common_pool)
 {
   SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
   SVN_ERR(initialize_fs_struct(fs));
 
-  SVN_ERR(svn_fs_fs__create(fs, path, pool));
+  SVN_ERR(svn_fs_fs__create(fs, path, scratch_pool));
 
-  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
+  SVN_ERR(svn_fs_fs__initialize_caches(fs, scratch_pool));
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       fs_serialized_init(fs, common_pool, pool));
+                       fs_serialized_init(fs, common_pool, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -320,10 +344,10 @@ static svn_error_t *
 fs_open(svn_fs_t *fs,
         const char *path,
         svn_mutex__t *common_pool_lock,
-        apr_pool_t *pool,
+        apr_pool_t *scratch_pool,
         apr_pool_t *common_pool)
 {
-  apr_pool_t *subpool = svn_pool_create(pool);
+  apr_pool_t *subpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
@@ -479,28 +503,19 @@ fs_hotcopy(svn_fs_t *src_fs,
            apr_pool_t *pool,
            apr_pool_t *common_pool)
 {
-  /* Open the source repo as usual. */
   SVN_ERR(fs_open(src_fs, src_path, common_pool_lock, pool, common_pool));
-  if (cancel_func)
-    SVN_ERR(cancel_func(cancel_baton));
 
-  /* Test target repo when in INCREMENTAL mode, initialize it when not.
-   * For this, we need our FS internal data structures to be temporarily
-   * available. */
+  SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
   SVN_ERR(initialize_fs_struct(dst_fs));
-  SVN_ERR(svn_fs_fs__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
-                                            incremental, pool));
-  uninitialize_fs_struct(dst_fs);
-
-  /* Now, the destination repo should open just fine. */
-  SVN_ERR(fs_open(dst_fs, dst_path, common_pool_lock, pool, common_pool));
-  if (cancel_func)
-    SVN_ERR(cancel_func(cancel_baton));
-
-  /* Now, we may copy data as needed ... */
-  return svn_fs_fs__hotcopy(src_fs, dst_fs, incremental,
-                            notify_func, notify_baton,
-                            cancel_func, cancel_baton, pool);
+
+  /* In INCREMENTAL mode, svn_fs_fs__hotcopy() will open DST_FS.
+     Otherwise, it's not an FS yet --- possibly just an empty dir --- so
+     can't be opened.
+   */
+  return svn_fs_fs__hotcopy(src_fs, dst_fs, src_path, dst_path,
+                            incremental, notify_func, notify_baton,
+                            cancel_func, cancel_baton, common_pool_lock,
+                            pool, common_pool);
 }
 
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h Mon Nov 30 10:24:16 2015
@@ -82,8 +82,6 @@ extern "C" {
 /* Names of special files and file extensions for transactions */
 #define PATH_CHANGES       "changes"       /* Records changes made so far */
 #define PATH_TXN_PROPS     "props"         /* Transaction properties */
-#define PATH_TXN_PROPS_FINAL "props-final" /* Final transaction properties
-                                              before moving to revprops */
 #define PATH_NEXT_IDS      "next-ids"      /* Next temporary ID assignments */
 #define PATH_PREFIX_NODE   "node."         /* Prefix for node filename */
 #define PATH_EXT_TXN       ".txn"          /* Extension of txn dir */
@@ -353,6 +351,15 @@ typedef struct fs_fs_data_t
      rep key (revision/offset) to svn_stringbuf_t. */
   svn_cache__t *fulltext_cache;
 
+  /* The current prefix to be used for revprop cache entries.
+     If this is 0, a new unique prefix must be chosen. */
+  apr_uint64_t revprop_prefix;
+
+  /* Revision property cache.  Maps from (rev,prefix) to apr_hash_t.
+     Unparsed svn_string_t representations of the serialized hash
+     will be written to the cache but the getter returns apr_hash_t. */
+  svn_cache__t *revprop_cache;
+
   /* Node properties cache.  Maps from rep key to apr_hash_t. */
   svn_cache__t *properties_cache;
 
@@ -478,10 +485,6 @@ typedef struct fs_fs_data_t
 /*** Filesystem Transaction ***/
 typedef struct transaction_t
 {
-  /* property list (const char * name, svn_string_t * value).
-     may be NULL if there are no properties.  */
-  apr_hash_t *proplist;
-
   /* node revision id of the root node.  */
   const svn_fs_id_t *root_id;
 
@@ -527,7 +530,14 @@ typedef struct representation_t
   svn_filesize_t size;
 
   /* The size of the fulltext of the representation. If this is 0,
-   * the fulltext size is equal to representation size in the rev file, */
+   * for a plain rep, the real fulltext size is equal to the SIZE field.
+   * For a delta rep, this field is always the real fulltext size.
+   *
+   * Note that svn_fs_fs__fixup_expanded_size() checks for these special
+   * cases and ensures that this field contains the actual value.  We call
+   * it early after reading a representation struct, so most code does not
+   * have to worry about it.
+   */
   svn_filesize_t expanded_size;
 
   /* Is this a representation (still) within a transaction? */
@@ -536,13 +546,7 @@ typedef struct representation_t
   /* For rep-sharing, we need a way of uniquifying node-revs which share the
      same representation (see svn_fs_fs__noderev_same_rep_key() ).  So, we
      store the original txn of the node rev (not the rep!), along with some
-     intra-node uniqification content.
-
-     This is no longer used by the 1.9 code but we have to keep
-     reading and writing it for old formats to remain compatible with
-     1.8, and earlier, that require it.  We also read/write it in
-     format 7 even though it is not currently required by any code
-     that handles that format. */
+     intra-node uniqification content. */
   struct
     {
       /* unique context, i.e. txn ID, in which the noderev (!) got created */
@@ -616,6 +620,18 @@ typedef struct change_t
   svn_fs_path_change2_t info;
 } change_t;
 
+
+/*** Directory (only used at the cache interface) ***/
+typedef struct svn_fs_fs__dir_data_t
+{
+  /* Contents, i.e. all directory entries, sorted by name. */
+  apr_array_header_t *entries;
+
+  /* SVN_INVALID_FILESIZE for committed data, otherwise the length of the
+   * in-txn on-disk representation of that directory. */
+  svn_filesize_t txn_filesize;
+} svn_fs_fs__dir_data_t;
+
 
 #ifdef __cplusplus
 }