You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2012/10/30 21:03:39 UTC

svn commit: r1403849 [7/19] - in /subversion/branches/master-passphrase: ./ build/ build/ac-macros/ build/hudson/ contrib/server-side/fsfsfixer/ notes/ notes/api-errata/1.8/ notes/directory-index/ notes/obliterate/ notes/tree-conflicts/ subversion/bind...

Modified: subversion/branches/master-passphrase/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_client/switch.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_client/switch.c Tue Oct 30 20:03:28 2012
@@ -79,6 +79,8 @@ switch_internal(svn_revnum_t *result_rev
   svn_revnum_t revnum;
   svn_error_t *err = SVN_NO_ERROR;
   const char *diff3_cmd;
+  apr_hash_t *wcroot_iprops;
+  apr_array_header_t *inherited_props;
   svn_boolean_t use_commit_times;
   svn_boolean_t sleep_here = FALSE;
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
@@ -218,6 +220,62 @@ switch_internal(svn_revnum_t *result_rev
                                  svn_dirent_dirname(local_abspath, pool));
     }
 
+  wcroot_iprops = apr_hash_make(pool);
+  
+  /* Will the base of LOCAL_ABSPATH require an iprop cache post-switch?
+     If we are switching LOCAL_ABSPATH to the root of the repository then
+     we don't need to cache inherited properties.  In all other cases we
+     *might* need to cache iprops. */
+  if (strcmp(switch_loc->repos_root_url, switch_loc->url) != 0)
+    {
+      svn_boolean_t wc_root;
+      svn_boolean_t needs_iprop_cache = TRUE;
+
+      SVN_ERR(svn_wc__strictly_is_wc_root(&wc_root,
+                                          ctx->wc_ctx,
+                                          local_abspath,
+                                          pool));
+
+      /* Switching the WC root to anything but the repos root means
+         we need an iprop cache. */ 
+      if (!wc_root)
+        {
+          /* We know we are switching a subtree to something other than the
+             repos root, but if we are unswitching that subtree we don't
+             need an iprops cache. */
+          const char *target_parent_url;
+          const char *unswitched_url;
+
+          /* Calculate the URL LOCAL_ABSPATH would have if it was unswitched
+             relative to its parent. */
+          SVN_ERR(svn_wc__node_get_url(&target_parent_url, ctx->wc_ctx,
+                                       svn_dirent_dirname(local_abspath,
+                                                          pool),
+                                       pool, pool));
+          unswitched_url = svn_path_url_add_component2(
+            target_parent_url,
+            svn_dirent_basename(local_abspath, pool),
+            pool);
+
+          /* If LOCAL_ABSPATH will be unswitched relative to its parent, then
+             it doesn't need an iprop cache.  Note: It doesn't matter if
+             LOCAL_ABSPATH is withing a switched subtree, only if it's the
+             *root* of a switched subtree.*/
+          if (strcmp(unswitched_url, switch_loc->url) == 0)
+            needs_iprop_cache = FALSE;
+      }
+
+
+      if (needs_iprop_cache)
+        {
+          SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
+                                             "", switch_loc->rev, pool,
+                                             pool));
+          apr_hash_set(wcroot_iprops, local_abspath, APR_HASH_KEY_STRING,
+                       inherited_props);
+        }
+    }
+
   SVN_ERR(svn_ra_reparent(ra_session, anchor_url, pool));
 
   /* Fetch the switch (update) editor.  If REVISION is invalid, that's
@@ -231,8 +289,8 @@ switch_internal(svn_revnum_t *result_rev
 
   SVN_ERR(svn_wc__get_switch_editor(&switch_editor, &switch_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
-                                    target, switch_loc->url, use_commit_times,
-                                    depth,
+                                    target, switch_loc->url, wcroot_iprops,
+                                    use_commit_times, depth,
                                     depth_is_sticky, allow_unver_obstructions,
                                     server_supports_depth,
                                     diff3_cmd, preserved_exts,

Modified: subversion/branches/master-passphrase/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_client/update.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_client/update.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_client/update.c Tue Oct 30 20:03:28 2012
@@ -201,6 +201,8 @@ update_internal(svn_revnum_t *result_rev
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
   svn_boolean_t clean_checkout = FALSE;
   const char *diff3_cmd;
+  apr_hash_t *wcroot_iprops;
+  svn_opt_revision_t opt_rev;
   svn_ra_session_t *ra_session;
   const char *preserved_exts_str;
   apr_array_header_t *preserved_exts;
@@ -353,10 +355,18 @@ update_internal(svn_revnum_t *result_rev
       anchor_loc->url = corrected_url;
     }
 
+  /* Resolve unspecified REVISION now, because we need to retrieve the
+     correct inherited props prior to the editor drive and we need to
+     use the same value of HEAD for both. */
+  opt_rev.kind = revision->kind;
+  opt_rev.value = revision->value;
+  if (opt_rev.kind == svn_opt_revision_unspecified)
+    opt_rev.kind = svn_opt_revision_head;
+
   /* ### todo: shouldn't svn_client__get_revision_number be able
      to take a URL as easily as a local path?  */
   SVN_ERR(svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
-                                          local_abspath, ra_session, revision,
+                                          local_abspath, ra_session, &opt_rev,
                                           pool));
 
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
@@ -366,12 +376,31 @@ update_internal(svn_revnum_t *result_rev
   dfb.target_revision = revnum;
   dfb.anchor_url = anchor_loc->url;
 
+  err = svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
+                                          revnum, depth, ra_session, ctx,
+                                          pool, pool);
+
+  /* We might be trying to update to a non-existant path-rev. */
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          err = NULL;
+        }
+      else
+        {
+          return svn_error_trace(err);
+        }
+    }
+
   /* Fetch the update editor.  If REVISION is invalid, that's okay;
      the RA driver will call editor->set_target_revision later on. */
   SVN_ERR(svn_wc__get_update_editor(&update_editor, &update_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
-                                    target, use_commit_times, depth,
-                                    depth_is_sticky, allow_unver_obstructions,
+                                    target, wcroot_iprops, use_commit_times,
+                                    depth, depth_is_sticky,
+                                    allow_unver_obstructions,
                                     adds_as_modification,
                                     server_supports_depth,
                                     clean_checkout,

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/compat.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/compat.c Tue Oct 30 20:03:28 2012
@@ -1637,9 +1637,12 @@ apply_change(void **dir_baton,
                                                        change->copyfrom_path,
                                                        scratch_pool);
           else
-            /* ### prefix with "/" ?  */
             copyfrom_url = change->copyfrom_path;
 
+          /* Make this an FS path by prepending "/" */
+          if (copyfrom_url[0] != '/')
+            copyfrom_url = apr_pstrcat(scratch_pool, "/", copyfrom_url, NULL);
+
           copyfrom_rev = change->copyfrom_rev;
         }
 
@@ -1722,27 +1725,8 @@ drive_changes(const struct editor_baton 
 
   /* Get a sorted list of Ev1-relative paths.  */
   paths = get_sorted_paths(eb->changes, eb->base_relpath, scratch_pool);
-
-  /* We need to pass SVN_INVALID_REVNUM to the path_driver. It uses this
-     revision whenever it opens directory batons. If we specified a "real"
-     value, such as eb->root.base_revision, then it might use that for a
-     subdirectory *incorrectly*.
-
-     Specifically, log_tests 38 demonstrates that erroneous behavior when
-     it attempts to open "/A" at revision 0 (not there, of course).
-
-     All this said: passing SVN_INVALID_REVNUM to all of those
-     open_directory() calls is not the best behavior either, but it does
-     happen to magically work. (ugh)
-
-     Thankfully, we're moving away from this skitchy behavior to Ev2.
-
-     Final note: every other caller of svn_delta_path_driver() passes
-     SVN_INVALID_REVNUM, so we can't be the only goofball.
-
-     Note: dropping const on the callback_baton.  */
   SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton, paths,
-                                 apply_change, (void *)eb,
+                                 FALSE, apply_change, (void *)eb,
                                  scratch_pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/deprecated.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/deprecated.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/deprecated.c Tue Oct 30 20:03:28 2012
@@ -39,15 +39,10 @@ svn_delta_path_driver(const svn_delta_ed
                       void *callback_baton,
                       apr_pool_t *scratch_pool)
 {
-  apr_array_header_t *sorted;
-
   /* REVISION is dropped on the floor.  */
 
-  /* Construct a copy of PATHS, then sort them in a depth-first order.  */
-  sorted = apr_array_copy(scratch_pool, paths);
-  qsort(sorted->elts, sorted->nelts, sorted->elt_size, svn_sort_compare_paths);
-
-  return svn_error_trace(svn_delta_path_driver2(editor, edit_baton, sorted,
+  return svn_error_trace(svn_delta_path_driver2(editor, edit_baton, paths,
+                                                TRUE,
                                                 callback_func, callback_baton,
                                                 scratch_pool));
 }

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/editor.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/editor.c Tue Oct 30 20:03:28 2012
@@ -77,23 +77,23 @@ struct svn_editor_t
 #define END_CALLBACK(editor) ((editor)->within_callback = FALSE)
 
 /* Marker to indicate no further changes are allowed on this node.  */
-static const int marker_done;
+static const int marker_done = 0;
 #define MARKER_DONE (&marker_done)
 
 /* Marker indicating that add_* may be called for this path, or that it
    can be the destination of a copy or move. For copy/move, the path
    will switch to MARKER_ALLOW_ALTER, to enable further tweaks.  */
-static const int marker_allow_add;
+static const int marker_allow_add = 0;
 #define MARKER_ALLOW_ADD (&marker_allow_add)
 
 /* Marker indicating that alter_* may be called for this path.  */
-static const int marker_allow_alter;
+static const int marker_allow_alter = 0;
 #define MARKER_ALLOW_ALTER (&marker_allow_alter)
 
 /* Just like MARKER_DONE, but also indicates that the node was created
    via add_directory(). This allows us to verify that the CHILDREN param
    was comprehensive.  */
-static const int marker_added_dir;
+static const int marker_added_dir = 0;
 #define MARKER_ADDED_DIR (&marker_added_dir)
 
 #define MARK_FINISHED(editor) ((editor)->finished = TRUE)

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/path_driver.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/path_driver.c Tue Oct 30 20:03:28 2012
@@ -133,6 +133,7 @@ svn_error_t *
 svn_delta_path_driver2(const svn_delta_editor_t *editor,
                        void *edit_baton,
                        const apr_array_header_t *paths,
+                       svn_boolean_t sort_paths,
                        svn_delta_path_driver_cb_func_t callback_func,
                        void *callback_baton,
                        apr_pool_t *pool)
@@ -151,6 +152,16 @@ svn_delta_path_driver2(const svn_delta_e
 
   subpool = svn_pool_create(pool);
   iterpool = svn_pool_create(pool);
+
+  /* sort paths if necessary */
+  if (sort_paths && paths->nelts > 1)
+    {
+      apr_array_header_t *sorted = apr_array_copy(subpool, paths);
+      qsort(sorted->elts, sorted->nelts, sorted->elt_size,
+            svn_sort_compare_paths);
+      paths = sorted;
+    }
+
   item = apr_pcalloc(subpool, sizeof(*item));
 
   /* If the root of the edit is also a target path, we want to call

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/svndiff.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/svndiff.c Tue Oct 30 20:03:28 2012
@@ -186,18 +186,86 @@ zlib_encode(const char *data,
 }
 
 static svn_error_t *
+send_simple_insertion_window(svn_txdelta_window_t *window,
+                             struct encoder_baton *eb)
+{
+  unsigned char headers[4 + 5 * MAX_ENCODED_INT_LEN + MAX_INSTRUCTION_LEN];
+  unsigned char ibuf[MAX_INSTRUCTION_LEN];
+  unsigned char *header_current;
+  apr_size_t header_len;
+  apr_size_t ip_len, i;
+  apr_size_t len = window->new_data->len;
+
+  /* there is only one target copy op. It must span the whole window */
+  assert(window->ops[0].action_code == svn_txdelta_new);
+  assert(window->ops[0].length == window->tview_len);
+  assert(window->ops[0].offset == 0);
+
+  /* write stream header if necessary */
+  if (eb->header_done == FALSE)
+    {
+      eb->header_done = TRUE;
+      headers[0] = 'S';
+      headers[1] = 'V';
+      headers[2] = 'N';
+      headers[3] = (unsigned char)eb->version;
+      header_current = headers + 4;
+    }
+  else
+    {
+      header_current = headers;
+    }
+    
+  /* Encode the action code and length.  */
+  if (window->tview_len >> 6 == 0)
+    {
+      ibuf[0] = (unsigned char)(window->tview_len + (0x2 << 6));
+      ip_len = 1;
+    }
+  else
+    {
+      ibuf[0] = (0x2 << 6);
+      ip_len = encode_int(ibuf + 1, window->tview_len) - ibuf;
+    }
+
+  /* encode the window header.  */
+  header_current[0] = 0;  /* source offset == 0 */
+  header_current[1] = 0;  /* source length == 0 */
+  header_current = encode_int(header_current + 2, window->tview_len);
+  header_current[0] = (unsigned char)ip_len;  /* 1 instruction */
+  header_current = encode_int(&header_current[1], len);
+
+  /* append instructions (1 to a handful of bytes) */
+  for (i = 0; i < ip_len; ++i)
+    header_current[i] = ibuf[i];
+
+  header_len = header_current - headers + ip_len;
+    
+  /* Write out the window.  */
+  SVN_ERR(svn_stream_write(eb->output, (const char *)headers, &header_len));
+  if (len)
+    SVN_ERR(svn_stream_write(eb->output, window->new_data->data, &len));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 window_handler(svn_txdelta_window_t *window, void *baton)
 {
   struct encoder_baton *eb = baton;
-  apr_pool_t *pool = svn_pool_create(eb->pool);
-  svn_stringbuf_t *instructions = svn_stringbuf_create_empty(pool);
-  svn_stringbuf_t *i1 = svn_stringbuf_create_empty(pool);
-  svn_stringbuf_t *header = svn_stringbuf_create_empty(pool);
+  apr_pool_t *pool;
+  svn_stringbuf_t *instructions;
+  svn_stringbuf_t *i1;
+  svn_stringbuf_t *header;
   const svn_string_t *newdata;
   unsigned char ibuf[MAX_INSTRUCTION_LEN], *ip;
   const svn_txdelta_op_t *op;
   apr_size_t len;
 
+  /* use specialized code if there is no source */
+  if (window && !window->src_ops && window->num_ops == 1 && !eb->version)
+    return svn_error_trace(send_simple_insertion_window(window, eb));
+
   /* Make sure we write the header.  */
   if (eb->header_done == FALSE)
     {
@@ -229,6 +297,12 @@ window_handler(svn_txdelta_window_t *win
       return svn_stream_close(output);
     }
 
+  /* create the necessary data buffers */
+  pool = svn_pool_create(eb->pool);
+  instructions = svn_stringbuf_create_empty(pool);
+  i1 = svn_stringbuf_create_empty(pool);
+  header = svn_stringbuf_create_empty(pool);
+
   /* Encode the instructions.  */
   for (op = window->ops; op < window->ops + window->num_ops; op++)
     {
@@ -450,7 +524,7 @@ decode_size(apr_size_t *val,
  */
 static svn_error_t *
 zlib_decode(const unsigned char *in, apr_size_t inLen, svn_stringbuf_t *out,
-            apr_size_t limit, svn_boolean_t copyless_allowed)
+            apr_size_t limit)
 {
   apr_size_t len;
   const unsigned char *oldplace = in;
@@ -469,22 +543,10 @@ zlib_decode(const unsigned char *in, apr
   inLen -= (in - oldplace);
   if (inLen == len)
     {
-      if (copyless_allowed)
-        {
-          /* "in" is no longer used but the memory remains allocated for
-           * at least as long as "out" will be used by the caller.
-           */
-          out->data = (char *)in;
-          out->len = len;
-          out->blocksize = len; /* sic! */
-        }
-      else
-        {
-          svn_stringbuf_ensure(out, len);
-          memcpy(out->data, in, len);
-          out->data[len] = 0;
-          out->len = len;
-        }
+      svn_stringbuf_ensure(out, len);
+      memcpy(out->data, in, len);
+      out->data[len] = 0;
+      out->len = len;
 
       return SVN_NO_ERROR;
     }
@@ -661,9 +723,9 @@ decode_window(svn_txdelta_window_t *wind
       /* these may in fact simply return references to insend */
 
       SVN_ERR(zlib_decode(insend, newlen, ndout,
-                          SVN_DELTA_WINDOW_SIZE, TRUE));
+                          SVN_DELTA_WINDOW_SIZE));
       SVN_ERR(zlib_decode(data, insend - data, instout,
-                          MAX_INSTRUCTION_SECTION_LEN, TRUE));
+                          MAX_INSTRUCTION_SECTION_LEN));
 
       newlen = ndout->len;
       data = (unsigned char *)instout->data;
@@ -1008,8 +1070,7 @@ svn__compress(svn_string_t *in,
               svn_stringbuf_t *out,
               int compression_level)
 {
-  return zlib_encode(in->data, in->len, out,
-                     compression_level);
+  return zlib_encode(in->data, in->len, out, compression_level);
 }
 
 svn_error_t *
@@ -1017,6 +1078,5 @@ svn__decompress(svn_string_t *in,
                 svn_stringbuf_t *out,
                 apr_size_t limit)
 {
-  return zlib_decode((const unsigned char*)in->data, in->len, out, limit,
-                     FALSE);
+  return zlib_decode((const unsigned char*)in->data, in->len, out, limit);
 }

Modified: subversion/branches/master-passphrase/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_delta/text_delta.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_delta/text_delta.c Tue Oct 30 20:03:28 2012
@@ -998,3 +998,42 @@ svn_error_t *svn_txdelta_send_txstream(s
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_txdelta_send_contents(const unsigned char *contents,
+                          apr_size_t len,
+                          svn_txdelta_window_handler_t handler,
+                          void *handler_baton,
+                          apr_pool_t *pool)
+{
+  svn_string_t new_data;
+  svn_txdelta_op_t op = { svn_txdelta_new, 0, 0 };
+  svn_txdelta_window_t window = { 0, 0, 0, 1, 0 };
+  window.ops = &op;
+  window.new_data = &new_data;
+
+  /* send CONTENT as a series of max-sized windows */
+  while (len > 0)
+    {
+      /* stuff next chunk into the window */
+      window.tview_len = len < SVN_DELTA_WINDOW_SIZE
+                       ? len
+                       : SVN_DELTA_WINDOW_SIZE;
+      op.length = window.tview_len;
+      new_data.len = window.tview_len;
+      new_data.data = (const char*)contents;
+
+      /* update remaining */
+      contents += window.tview_len;
+      len -= window.tview_len;
+
+      /* shove it at the handler */
+      SVN_ERR((*handler)(&window, handler_baton));
+    }
+
+  /* indicate end of stream */
+  SVN_ERR((*handler)(NULL, handler_baton));
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/branches/master-passphrase/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_diff/parse-diff.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_diff/parse-diff.c Tue Oct 30 20:03:28 2012
@@ -595,7 +595,6 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                     original_end = hunk_text_end;
                   if (modified_end == 0)
                     modified_end = hunk_text_end;
-                  break;
                 }
 
               SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.c Tue Oct 30 20:03:28 2012
@@ -1204,6 +1204,27 @@ svn_fs_file_contents(svn_stream_t **cont
 }
 
 svn_error_t *
+svn_fs_try_process_file_contents(svn_boolean_t *success,
+                                 svn_fs_root_t *root,
+                                 const char *path,
+                                 svn_fs_process_contents_func_t processor,
+                                 void* baton,
+                                 apr_pool_t *pool)
+{
+  /* if the FS doesn't implement this function, report a "failed" attempt */
+  if (root->vtable->try_process_file_contents == NULL)
+    {
+      *success = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  return svn_error_trace(root->vtable->try_process_file_contents(
+                         success,
+                         root, path,
+                         processor, baton, pool));
+}
+
+svn_error_t *
 svn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
   SVN_ERR(svn_fs__path_valid(path, pool));

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs/fs-loader.h Tue Oct 30 20:03:28 2012
@@ -306,6 +306,12 @@ typedef struct root_vtable_t
   svn_error_t *(*file_contents)(svn_stream_t **contents,
                                 svn_fs_root_t *root, const char *path,
                                 apr_pool_t *pool);
+  svn_error_t *(*try_process_file_contents)(svn_boolean_t *success,
+                                            svn_fs_root_t *target_root,
+                                            const char *target_path,
+                                            svn_fs_process_contents_func_t processor,
+                                            void* baton,
+                                            apr_pool_t *pool);
   svn_error_t *(*make_file)(svn_fs_root_t *root, const char *path,
                             apr_pool_t *pool);
   svn_error_t *(*apply_textdelta)(svn_txdelta_window_handler_t *contents_p,

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_base/tree.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_base/tree.c Tue Oct 30 20:03:28 2012
@@ -5387,6 +5387,7 @@ static root_vtable_t root_vtable = {
   base_file_length,
   base_file_checksum,
   base_file_contents,
+  NULL,
   base_make_file,
   base_apply_textdelta,
   base_apply_text,

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/caching.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/caching.c Tue Oct 30 20:03:28 2012
@@ -24,6 +24,7 @@
 #include "fs_fs.h"
 #include "id.h"
 #include "dag.h"
+#include "tree.h"
 #include "temp_serializer.h"
 #include "../libsvn_fs/fs-loader.h"
 
@@ -32,6 +33,8 @@
 
 #include "svn_private_config.h"
 #include "svn_hash.h"
+#include "svn_pools.h"
+
 #include "private/svn_debug.h"
 #include "private/svn_subr_private.h"
 
@@ -92,18 +95,34 @@ read_config(svn_memcache_t **memcache_p,
 }
 
 
-/* Implements svn_cache__error_handler_t */
+/* Implements svn_cache__error_handler_t
+ * This variant clears the error after logging it.
+ */
 static svn_error_t *
-warn_on_cache_errors(svn_error_t *err,
-                     void *baton,
-                     apr_pool_t *pool)
+warn_and_continue_on_cache_errors(svn_error_t *err,
+                                  void *baton,
+                                  apr_pool_t *pool)
 {
   svn_fs_t *fs = baton;
   (fs->warning)(fs->warning_baton, err);
   svn_error_clear(err);
+
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_cache__error_handler_t
+ * This variant logs the error and passes it on to the callers.
+ */
+static svn_error_t *
+warn_and_fail_on_cache_errors(svn_error_t *err,
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  svn_fs_t *fs = baton;
+  (fs->warning)(fs->warning_baton, err);
+  return err;
+}
+
 #ifdef SVN_DEBUG_CACHE_DUMP_STATS
 /* Baton to be used for the dump_cache_statistics() pool cleanup function, */
 struct dump_cache_baton_t
@@ -162,13 +181,12 @@ dump_cache_statistics(void *baton_void)
  * not transaction-specific CACHE object in FS, if CACHE is not NULL.
  *
  * All these svn_cache__t instances shall be handled uniformly. Unless
- * NO_HANDLER is true, register an error handler that reports errors
- * as warnings for the given CACHE.
+ * ERROR_HANDLER is NULL, register it for the given CACHE in FS.
  */
 static svn_error_t *
 init_callbacks(svn_cache__t *cache,
                svn_fs_t *fs,
-               svn_boolean_t no_handler,
+               svn_cache__error_handler_t error_handler,
                apr_pool_t *pool)
 {
   if (cache != NULL)
@@ -190,9 +208,9 @@ init_callbacks(svn_cache__t *cache,
                                 apr_pool_cleanup_null);
 #endif
 
-      if (! no_handler)
+      if (error_handler)
         SVN_ERR(svn_cache__set_error_handler(cache,
-                                             warn_on_cache_errors,
+                                             error_handler,
                                              fs,
                                              pool));
 
@@ -207,6 +225,9 @@ init_callbacks(svn_cache__t *cache,
  * MEMBUFFER are NULL and pages is non-zero.  Sets *CACHE_P to NULL
  * otherwise.
  *
+ * Unless NO_HANDLER is true, register an error handler that reports errors
+ * as warnings to the FS warning callback.
+ * 
  * Cache is allocated in POOL.
  * */
 static svn_error_t *
@@ -219,32 +240,43 @@ create_cache(svn_cache__t **cache_p,
              svn_cache__deserialize_func_t deserializer,
              apr_ssize_t klen,
              const char *prefix,
+             svn_fs_t *fs,
+             svn_boolean_t no_handler,
              apr_pool_t *pool)
 {
-    if (memcache)
-      {
-        SVN_ERR(svn_cache__create_memcache(cache_p, memcache,
-                                           serializer, deserializer, klen,
-                                           prefix, pool));
-      }
-    else if (membuffer)
-      {
-        SVN_ERR(svn_cache__create_membuffer_cache(
-                  cache_p, membuffer, serializer, deserializer,
-                  klen, prefix, FALSE, pool));
-      }
-    else if (pages)
-      {
-        SVN_ERR(svn_cache__create_inprocess(
-                  cache_p, serializer, deserializer, klen, pages,
-                  items_per_page, FALSE, prefix, pool));
-      }
-    else
+  svn_cache__error_handler_t error_handler = no_handler
+                                           ? NULL
+                                           : warn_and_fail_on_cache_errors;
+
+  if (memcache)
+    {
+      SVN_ERR(svn_cache__create_memcache(cache_p, memcache,
+                                         serializer, deserializer, klen,
+                                         prefix, pool));
+      error_handler = no_handler
+                    ? NULL
+                    : warn_and_continue_on_cache_errors;
+    }
+  else if (membuffer)
+    {
+      SVN_ERR(svn_cache__create_membuffer_cache(
+                cache_p, membuffer, serializer, deserializer,
+                klen, prefix, FALSE, pool));
+    }
+  else if (pages)
+    {
+      SVN_ERR(svn_cache__create_inprocess(
+                cache_p, serializer, deserializer, klen, pages,
+                items_per_page, FALSE, prefix, pool));
+    }
+  else
     {
       *cache_p = NULL;
     }
 
-    return SVN_NO_ERROR;
+  SVN_ERR(init_callbacks(*cache_p, fs, error_handler, pool));
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -290,10 +322,10 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        svn_fs_fs__deserialize_id,
                        sizeof(svn_revnum_t),
                        apr_pstrcat(pool, prefix, "RRI", (char *)NULL),
+                       fs,
+                       no_handler,
                        fs->pool));
 
-  SVN_ERR(init_callbacks(ffd->rev_root_id_cache, fs, no_handler, pool));
-
   /* Rough estimate: revision DAG nodes have size around 320 bytes, so
    * let's put 16 on a page. */
   SVN_ERR(create_cache(&(ffd->rev_node_cache),
@@ -304,9 +336,12 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        svn_fs_fs__dag_deserialize,
                        APR_HASH_KEY_STRING,
                        apr_pstrcat(pool, prefix, "DAG", (char *)NULL),
+                       fs,
+                       no_handler,
                        fs->pool));
 
-  SVN_ERR(init_callbacks(ffd->rev_node_cache, fs, no_handler, pool));
+  /* 1st level DAG node cache */
+  ffd->dag_node_cache = svn_fs_fs__create_dag_cache(pool);
 
   /* Very rough estimate: 1K per directory. */
   SVN_ERR(create_cache(&(ffd->dir_cache),
@@ -317,10 +352,10 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        svn_fs_fs__deserialize_dir_entries,
                        APR_HASH_KEY_STRING,
                        apr_pstrcat(pool, prefix, "DIR", (char *)NULL),
+                       fs,
+                       no_handler,
                        fs->pool));
 
-  SVN_ERR(init_callbacks(ffd->dir_cache, fs, no_handler, pool));
-
   /* Only 16 bytes per entry (a revision number + the corresponding offset).
      Since we want ~8k pages, that means 512 entries per page. */
   SVN_ERR(create_cache(&(ffd->packed_offset_cache),
@@ -332,12 +367,37 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        sizeof(svn_revnum_t),
                        apr_pstrcat(pool, prefix, "PACK-MANIFEST",
                                    (char *)NULL),
+                       fs,
+                       no_handler,
                        fs->pool));
 
-  SVN_ERR(init_callbacks(ffd->packed_offset_cache, fs, no_handler, pool));
+  /* initialize node revision cache, if caching has been enabled */
+  SVN_ERR(create_cache(&(ffd->node_revision_cache),
+                       NULL,
+                       membuffer,
+                       0, 0, /* Do not use inprocess cache */
+                       svn_fs_fs__serialize_node_revision,
+                       svn_fs_fs__deserialize_node_revision,
+                       sizeof(pair_cache_key_t),
+                       apr_pstrcat(pool, prefix, "NODEREVS", (char *)NULL),
+                       fs,
+                       no_handler,
+                       fs->pool));
 
-  /* initialize fulltext cache as configured */
-  ffd->fulltext_cache = NULL;
+  /* initialize node change list cache, if caching has been enabled */
+  SVN_ERR(create_cache(&(ffd->changes_cache),
+                       NULL,
+                       membuffer,
+                       0, 0, /* Do not use inprocess cache */
+                       svn_fs_fs__serialize_changes,
+                       svn_fs_fs__deserialize_changes,
+                       sizeof(svn_revnum_t),
+                       apr_pstrcat(pool, prefix, "CHANGES", (char *)NULL),
+                       fs,
+                       no_handler,
+                       fs->pool));
+
+  /* if enabled, cache fulltext and other derived information */
   if (cache_fulltexts)
     {
       SVN_ERR(create_cache(&(ffd->fulltext_cache),
@@ -346,12 +406,58 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                            0, 0, /* Do not use inprocess cache */
                            /* Values are svn_stringbuf_t */
                            NULL, NULL,
-                           APR_HASH_KEY_STRING,
+                           sizeof(pair_cache_key_t),
                            apr_pstrcat(pool, prefix, "TEXT", (char *)NULL),
+                           fs,
+                           no_handler,
+                           fs->pool));
+      
+      SVN_ERR(create_cache(&(ffd->properties_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           svn_fs_fs__serialize_properties,
+                           svn_fs_fs__deserialize_properties,
+                           sizeof(pair_cache_key_t),
+                           apr_pstrcat(pool, prefix, "PROP",
+                                       (char *)NULL),
+                           fs,
+                           no_handler,
+                           fs->pool));
+      
+      SVN_ERR(create_cache(&(ffd->mergeinfo_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           svn_fs_fs__serialize_mergeinfo,
+                           svn_fs_fs__deserialize_mergeinfo,
+                           APR_HASH_KEY_STRING,
+                           apr_pstrcat(pool, prefix, "MERGEINFO",
+                                       (char *)NULL),
+                           fs,
+                           no_handler,
+                           fs->pool));
+      
+      SVN_ERR(create_cache(&(ffd->mergeinfo_existence_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           /* Values are svn_stringbuf_t */
+                           NULL, NULL,
+                           APR_HASH_KEY_STRING,
+                           apr_pstrcat(pool, prefix, "HAS_MERGEINFO",
+                                       (char *)NULL),
+                           fs,
+                           no_handler,
                            fs->pool));
     }
-
-  SVN_ERR(init_callbacks(ffd->fulltext_cache, fs, no_handler, pool));
+  else
+    {
+      ffd->fulltext_cache = NULL;
+      ffd->properties_cache = NULL;
+      ffd->mergeinfo_cache = NULL;
+      ffd->mergeinfo_existence_cache = NULL;
+    }
 
   /* initialize revprop cache, if full-text caching has been enabled */
   if (cache_revprops)
@@ -362,9 +468,11 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                            0, 0, /* Do not use inprocess cache */
                            svn_fs_fs__serialize_properties,
                            svn_fs_fs__deserialize_properties,
-                           APR_HASH_KEY_STRING,
+                           sizeof(pair_cache_key_t),
                            apr_pstrcat(pool, prefix, "REVPROP",
                                        (char *)NULL),
+                           fs,
+                           no_handler,
                            fs->pool));
     }
   else
@@ -372,9 +480,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
       ffd->revprop_cache = NULL;
     }
 
-  SVN_ERR(init_callbacks(ffd->revprop_cache, fs, no_handler, pool));
-
-  /* initialize txdelta window cache, if that has been enabled */
+  /* if enabled, cache text deltas and their combinations */
   if (cache_txdeltas)
     {
       SVN_ERR(create_cache(&(ffd->txdelta_window_cache),
@@ -386,18 +492,10 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                            APR_HASH_KEY_STRING,
                            apr_pstrcat(pool, prefix, "TXDELTA_WINDOW",
                                        (char *)NULL),
+                           fs,
+                           no_handler,
                            fs->pool));
-    }
-  else
-    {
-      ffd->txdelta_window_cache = NULL;
-    }
-
-  SVN_ERR(init_callbacks(ffd->txdelta_window_cache, fs, no_handler, pool));
 
-  /* initialize txdelta window cache, if that has been enabled */
-  if (cache_txdeltas)
-    {
       SVN_ERR(create_cache(&(ffd->combined_window_cache),
                            NULL,
                            membuffer,
@@ -407,41 +505,16 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                            APR_HASH_KEY_STRING,
                            apr_pstrcat(pool, prefix, "COMBINED_WINDOW",
                                        (char *)NULL),
+                           fs,
+                           no_handler,
                            fs->pool));
     }
   else
     {
+      ffd->txdelta_window_cache = NULL;
       ffd->combined_window_cache = NULL;
     }
 
-  SVN_ERR(init_callbacks(ffd->combined_window_cache, fs, no_handler, pool));
-
-  /* initialize node revision cache, if caching has been enabled */
-  SVN_ERR(create_cache(&(ffd->node_revision_cache),
-                       NULL,
-                       membuffer,
-                       0, 0, /* Do not use inprocess cache */
-                       svn_fs_fs__serialize_node_revision,
-                       svn_fs_fs__deserialize_node_revision,
-                       APR_HASH_KEY_STRING,
-                       apr_pstrcat(pool, prefix, "NODEREVS", (char *)NULL),
-                       fs->pool));
-
-  SVN_ERR(init_callbacks(ffd->node_revision_cache, fs, no_handler, pool));
-
-  /* initialize node change list cache, if caching has been enabled */
-  SVN_ERR(create_cache(&(ffd->changes_cache),
-                       NULL,
-                       membuffer,
-                       0, 0, /* Do not use inprocess cache */
-                       svn_fs_fs__serialize_changes,
-                       svn_fs_fs__deserialize_changes,
-                       sizeof(svn_revnum_t),
-                       apr_pstrcat(pool, prefix, "CHANGES", (char *)NULL),
-                       fs->pool));
-
-  SVN_ERR(init_callbacks(ffd->changes_cache, fs, no_handler, pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -535,6 +608,8 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
                        APR_HASH_KEY_STRING,
                        apr_pstrcat(pool, prefix, "TXNDIR",
                                    (char *)NULL),
+                       fs,
+                       TRUE,
                        pool));
 
   /* reset the transaction-specific cache if the pool gets cleaned up. */

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.c Tue Oct 30 20:03:28 2012
@@ -947,6 +947,24 @@ svn_fs_fs__dag_get_file_delta_stream(svn
 
 
 svn_error_t *
+svn_fs_fs__dag_try_process_file_contents(svn_boolean_t *success,
+                                         dag_node_t *node,
+                                         svn_fs_process_contents_func_t processor,
+                                         void* baton,
+                                         apr_pool_t *pool)
+{
+  node_revision_t *noderev;
+
+  /* Go get fresh node-revisions for the nodes. */
+  SVN_ERR(get_node_revision(&noderev, node));
+
+  return svn_fs_fs__try_process_file_contents(success, node->fs,
+                                              noderev,
+                                              processor, baton, pool);
+}
+
+
+svn_error_t *
 svn_fs_fs__dag_file_length(svn_filesize_t *length,
                            dag_node_t *file,
                            apr_pool_t *pool)

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/dag.h Tue Oct 30 20:03:28 2012
@@ -403,6 +403,19 @@ svn_error_t *svn_fs_fs__dag_get_contents
                                          dag_node_t *file,
                                          apr_pool_t *pool);
 
+/* Attempt to fetch the contents of NODE and pass it along with the BATON
+   to the PROCESSOR.   Set *SUCCESS only of the data could be provided
+   and the processor had been called.
+
+   Use POOL for all allocations.
+ */
+svn_error_t *
+svn_fs_fs__dag_try_process_file_contents(svn_boolean_t *success,
+                                         dag_node_t *node,
+                                         svn_fs_process_contents_func_t processor,
+                                         void* baton,
+                                         apr_pool_t *pool);
+
 
 /* Set *STREAM_P to a delta stream that will turn the contents of SOURCE into
    the contents of TARGET, allocated in POOL.  If SOURCE is null, the empty

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs.h Tue Oct 30 20:03:28 2012
@@ -217,6 +217,17 @@ typedef struct fs_fs_shared_data_t
   apr_pool_t *common_pool;
 } fs_fs_shared_data_t;
 
+/* Data structure for the 1st level DAG node cache. */
+typedef struct fs_fs_dag_cache_t fs_fs_dag_cache_t;
+
+/* Key type for all caches that use revision + offset / counter as key. */
+typedef struct pair_cache_key_t
+{
+  svn_revnum_t revision;
+
+  apr_int64_t second;
+} pair_cache_key_t;
+
 /* Private (non-shared) FSFS-specific data for each svn_fs_t object.
    Any caches in here may be NULL. */
 typedef struct fs_fs_data_t
@@ -241,8 +252,11 @@ typedef struct fs_fs_data_t
      (svn_fs_id_t *).  (Not threadsafe.) */
   svn_cache__t *rev_root_id_cache;
 
+  /* Caches native dag_node_t* instances and acts as a 1st level cache */
+  fs_fs_dag_cache_t *dag_node_cache;
+
   /* DAG node cache for immutable nodes.  Maps (revision, fspath)
-     to (dag_node_t *). */
+     to (dag_node_t *). This is the 2nd level cache for DAG nodes. */
   svn_cache__t *rev_node_cache;
 
   /* A cache of the contents of immutable directories; maps from
@@ -269,6 +283,9 @@ typedef struct fs_fs_data_t
   /* Revision property cache.  Maps from (rev,generation) to apr_hash_t. */
   svn_cache__t *revprop_cache;
 
+  /* Node properties cache.  Maps from rep key to apr_hash_t. */
+  svn_cache__t *properties_cache;
+
   /* Pack manifest cache; a cache mapping (svn_revnum_t) shard number to
      a manifest; and a manifest is a mapping from (svn_revnum_t) revision
      number offset within a shard to (apr_off_t) byte-offset in the
@@ -289,6 +306,18 @@ typedef struct fs_fs_data_t
      is the revision */
   svn_cache__t *changes_cache;
 
+  /* Cache for svn_mergeinfo_t objects; the key is a combination of
+     revision, inheritance flags and path. */
+  svn_cache__t *mergeinfo_cache;
+
+  /* Cache for presence of svn_mergeinfo_t on a noderev; the key is a
+     combination of revision, inheritance flags and path; value is "1"
+     if the node has mergeinfo, "0" if it doesn't. */
+  svn_cache__t *mergeinfo_existence_cache;
+
+  /* TRUE while the we hold a lock on the write lock file. */
+  svn_boolean_t has_write_lock;
+
   /* If set, there are or have been more than one concurrent transaction */
   svn_boolean_t concurrent_transactions;
 

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.c Tue Oct 30 20:03:28 2012
@@ -98,7 +98,7 @@
 /* Give writing processes 10 seconds to replace an existing revprop
    file with a new one. After that time, we assume that the writing
    process got aborted and that we have re-read revprops. */
-#define REVPROP_CHANGE_TIMEOUT 10 * 1000000
+#define REVPROP_CHANGE_TIMEOUT (10 * 1000000)
 
 /* The following are names of atomics that will be used to communicate
  * revprop updates across all processes on this machine. */
@@ -589,16 +589,29 @@ get_lock_on_filesystem(const char *lock_
   return svn_error_trace(err);
 }
 
+/* Reset the HAS_WRITE_LOCK member in the FFD given as BATON_VOID.
+   When registered with the pool holding the lock on the lock file,
+   this makes sure the flag gets reset just before we release the lock. */
+static apr_status_t
+reset_lock_flag(void *baton_void)
+{
+  fs_fs_data_t *ffd = baton_void;
+  ffd->has_write_lock = FALSE;
+  return APR_SUCCESS;
+}
+
 /* Obtain a write lock on the file LOCK_FILENAME (protecting with
    LOCK_MUTEX if APR is threaded) in a subpool of POOL, call BODY with
    BATON and that subpool, destroy the subpool (releasing the write
-   lock) and return what BODY returned. */
+   lock) and return what BODY returned.  If IS_GLOBAL_LOCK is set,
+   set the HAS_WRITE_LOCK flag while we keep the write lock. */
 static svn_error_t *
 with_some_lock_file(svn_fs_t *fs,
                     svn_error_t *(*body)(void *baton,
                                          apr_pool_t *pool),
                     void *baton,
                     const char *lock_filename,
+                    svn_boolean_t is_global_lock,
                     apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -607,6 +620,19 @@ with_some_lock_file(svn_fs_t *fs,
   if (!err)
     {
       fs_fs_data_t *ffd = fs->fsap_data;
+
+      if (is_global_lock)
+        {
+          /* set the "got the lock" flag and register reset function */
+          apr_pool_cleanup_register(subpool,
+                                    ffd,
+                                    reset_lock_flag,
+                                    apr_pool_cleanup_null);
+          ffd->has_write_lock = TRUE;
+        }
+
+      /* nobody else will modify the repo state
+         => read HEAD & pack info once */
       if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
         SVN_ERR(update_min_unpacked_rev(fs, pool));
       SVN_ERR(get_youngest(&ffd->youngest_rev_cache, fs->path,
@@ -632,6 +658,7 @@ svn_fs_fs__with_write_lock(svn_fs_t *fs,
   SVN_MUTEX__WITH_LOCK(ffsd->fs_write_lock,
                        with_some_lock_file(fs, body, baton,
                                            path_lock(fs, pool),
+                                           TRUE,
                                            pool));
 
   return SVN_NO_ERROR;
@@ -652,6 +679,7 @@ with_txn_current_lock(svn_fs_t *fs,
   SVN_MUTEX__WITH_LOCK(ffsd->txn_current_lock,
                        with_some_lock_file(fs, body, baton,
                                            path_txn_current_lock(fs, pool),
+                                           FALSE,
                                            pool));
 
   return SVN_NO_ERROR;
@@ -2178,16 +2206,6 @@ err_dangling_id(svn_fs_t *fs, const svn_
      id_str->data, fs->path);
 }
 
-/* Return a string that uniquely identifies the noderev with the
- * given ID, for use as a cache key.
- */
-static const char *
-get_noderev_cache_key(const svn_fs_id_t *id, apr_pool_t *pool)
-{
-  const svn_string_t *id_unparsed = svn_fs_fs__id_unparse(id, pool);
-  return id_unparsed->data;
-}
-
 /* Look up the NODEREV_P for ID in FS' node revsion cache. If noderev
  * caching has been enabled and the data can be found, IS_CACHED will
  * be set to TRUE. The noderev will be allocated from POOL.
@@ -2203,13 +2221,19 @@ get_cached_node_revision_body(node_revis
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   if (! ffd->node_revision_cache || svn_fs_fs__id_txn_id(id))
-    *is_cached = FALSE;
+    {
+      *is_cached = FALSE;
+    }
   else
-    SVN_ERR(svn_cache__get((void **) noderev_p,
-                           is_cached,
-                           ffd->node_revision_cache,
-                           get_noderev_cache_key(id, pool),
-                           pool));
+    {
+      pair_cache_key_t key = { svn_fs_fs__id_rev(id),
+                               svn_fs_fs__id_offset(id) };
+      SVN_ERR(svn_cache__get((void **) noderev_p,
+                            is_cached,
+                            ffd->node_revision_cache,
+                            &key,
+                            pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2228,10 +2252,14 @@ set_cached_node_revision_body(node_revis
   fs_fs_data_t *ffd = fs->fsap_data;
 
   if (ffd->node_revision_cache && !svn_fs_fs__id_txn_id(id))
-    return svn_cache__set(ffd->node_revision_cache,
-                          get_noderev_cache_key(id, scratch_pool),
-                          noderev_p,
-                          scratch_pool);
+    {
+      pair_cache_key_t key = { svn_fs_fs__id_rev(id),
+                               svn_fs_fs__id_offset(id) };
+      return svn_cache__set(ffd->node_revision_cache,
+                            &key,
+                            noderev_p,
+                            scratch_pool);
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2585,6 +2613,10 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
   fs_fs_data_t *ffd = fs->fsap_data;
   apr_file_t *noderev_file;
   const char *txn_id = svn_fs_fs__id_txn_id(id);
+  const char *sha1 = ffd->rep_sharing_allowed && noderev->data_rep
+                   ? svn_checksum_to_cstring(noderev->data_rep->sha1_checksum,
+                                             pool)
+                   : NULL;
 
   noderev->is_fresh_txn_root = fresh_txn_root;
 
@@ -2603,7 +2635,32 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
                                    pool));
 
-  return svn_io_file_close(noderev_file, pool);
+  SVN_ERR(svn_io_file_close(noderev_file, pool));
+
+  /* if rep sharing has been enabled and the noderev has a data rep and
+   * its SHA-1 is known, store the rep struct under its SHA1. */
+  if (sha1)
+    {
+      apr_file_t *rep_file;
+      const char *file_name = svn_dirent_join(path_txn_dir(fs, txn_id, pool),
+                                              sha1, pool);
+      const char *rep_string = representation_string(noderev->data_rep,
+                                                     ffd->format,
+                                                     (noderev->kind
+                                                      == svn_node_dir),
+                                                     FALSE,
+                                                     pool);
+      SVN_ERR(svn_io_file_open(&rep_file, file_name,
+                               APR_WRITE | APR_CREATE | APR_TRUNCATE
+                               | APR_BUFFERED, APR_OS_DEFAULT, pool));
+
+      SVN_ERR(svn_io_file_write_full(rep_file, rep_string,
+                                     strlen(rep_string), NULL, pool));
+
+      SVN_ERR(svn_io_file_close(rep_file, pool));
+    }
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -3122,7 +3179,7 @@ ensure_revprop_generation(svn_fs_t *fs, 
                                     TRUE));
 
       /* If the generation is at 0, we just created a new namespace
-       * (it would be at least 2 otherwise). Read the lastest generation
+       * (it would be at least 2 otherwise). Read the latest generation
        * from disk and if we are the first one to initialize the atomic
        * (i.e. is still 0), set it to the value just gotten.
        */
@@ -3153,6 +3210,23 @@ ensure_revprop_timeout(svn_fs_t *fs)
     : SVN_NO_ERROR;
 }
 
+/* Create an error object with the given MESSAGE and pass it to the
+   WARNING member of FS. */
+static void
+log_revprop_cache_init_warning(svn_fs_t *fs,
+                               svn_error_t *underlying_err,
+                               const char *message)
+{
+  svn_error_t *err = svn_error_createf(SVN_ERR_FS_REPPROP_CACHE_INIT_FAILURE,
+                                       underlying_err,
+                                       message, fs->path);
+
+  if (fs->warning)
+    (fs->warning)(fs->warning_baton, err);
+  
+  svn_error_clear(err);
+}
+
 /* Test whether revprop cache and necessary infrastructure are
    available in FS. */
 static svn_boolean_t
@@ -3172,6 +3246,10 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
        * -> disable the revprop cache for good
        */
       ffd->revprop_cache = NULL;
+      log_revprop_cache_init_warning(fs, NULL,
+                                     "Revprop caching for '%s' disabled"
+                                     " because it would be inefficient.");
+      
       return FALSE;
     }
 
@@ -3181,8 +3259,11 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
     {
       /* failure -> disable revprop cache for good */
 
-      svn_error_clear(error);
       ffd->revprop_cache = NULL;
+      log_revprop_cache_init_warning(fs, error,
+                                     "Revprop caching for '%s' disabled "
+                                     "because SHM infrastructure for revprop "
+                                     "caching failed to initialize.");
 
       return FALSE;
     }
@@ -3190,6 +3271,46 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
   return TRUE;
 }
 
+/* Baton structure for revprop_generation_fixup. */
+typedef struct revprop_generation_fixup_t
+{
+  /* revprop generation to read */
+  apr_int64_t *generation;
+
+  /* containing the revprop_generation member to query */
+  fs_fs_data_t *ffd;
+} revprop_generation_upgrade_t;
+
+/* If the revprop generation has an odd value, it means the original writer
+   of the revprop got killed. We don't know whether that process as able
+   to change the revprop data but we assume that it was. Therefore, we
+   increase the generation in that case to basically invalidate everyones
+   cache content.
+   Execute this onlx while holding the write lock to the repo in baton->FFD.
+ */
+static svn_error_t *
+revprop_generation_fixup(void *void_baton,
+                         apr_pool_t *pool)
+{
+  revprop_generation_upgrade_t *baton = void_baton;
+  assert(baton->ffd->has_write_lock);
+  
+  /* Maybe, either the original revprop writer or some other reader has
+     already corrected / bumped the revprop generation.  Thus, we need
+     to read it again. */
+  SVN_ERR(svn_named_atomic__read(baton->generation,
+                                 baton->ffd->revprop_generation));
+
+  /* Cause everyone to re-read revprops upon their next access, if the
+     last revprop write did not complete properly. */
+  while (*baton->generation % 2)
+    SVN_ERR(svn_named_atomic__add(baton->generation,
+                                  1,
+                                  baton->ffd->revprop_generation));
+
+  return SVN_NO_ERROR;
+}
+
 /* Read the current revprop generation and return it in *GENERATION.
    Also, detect aborted / crashed writers and recover from that.
    Use the access object in FS to set the shared mem values. */
@@ -3219,13 +3340,19 @@ read_revprop_generation(apr_int64_t *gen
        */
       if (apr_time_now() > timeout)
         {
-          /* Cause everyone to re-read revprops upon their next access.
-           * Keep in mind that we may not be the only one trying to do it.
+          revprop_generation_upgrade_t baton;
+          baton.generation = &current;
+          baton.ffd = ffd;
+
+          /* Ensure that the original writer process no longer exists by
+           * acquiring the write lock to this repository.  Then, fix up
+           * the revprop generation.
            */
-          while (current % 2)
-            SVN_ERR(svn_named_atomic__add(&current,
-                                          1,
-                                          ffd->revprop_generation));
+          if (ffd->has_write_lock)
+            SVN_ERR(revprop_generation_fixup(&baton, pool));
+          else
+            SVN_ERR(svn_fs_fs__with_write_lock(fs, revprop_generation_fixup,
+                                               &baton, pool));
         }
     }
 
@@ -3366,12 +3493,10 @@ parse_revprop(apr_hash_t **properties,
   SVN_ERR(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR, pool));
   if (has_revprop_cache(fs, pool))
     {
-      const char *key;
+      pair_cache_key_t key = {revision, generation};
       fs_fs_data_t *ffd = fs->fsap_data;
 
-      key = svn_fs_fs__combine_two_numbers(revision, generation,
-                                           scratch_pool);
-      SVN_ERR(svn_cache__set(ffd->revprop_cache, key, *properties,
+      SVN_ERR(svn_cache__set(ffd->revprop_cache, &key, *properties,
                              scratch_pool));
     }
 
@@ -3512,8 +3637,8 @@ parse_packed_revprops(svn_fs_t *fs,
 
   revprops->packed_revprops = svn_stringbuf_create_empty(pool);
   revprops->packed_revprops->data = uncompressed->data + offset;
-  revprops->packed_revprops->len = uncompressed->len - offset;
-  revprops->packed_revprops->blocksize = uncompressed->blocksize - offset;
+  revprops->packed_revprops->len = (apr_size_t)(uncompressed->len - offset);
+  revprops->packed_revprops->blocksize = (apr_size_t)(uncompressed->blocksize - offset);
 
   /* STREAM still points to the first entry in the sizes list.
    * Init / construct REVPROPS members. */
@@ -3670,13 +3795,13 @@ get_revision_proplist(apr_hash_t **propl
   if (has_revprop_cache(fs, pool))
     {
       svn_boolean_t is_cached;
-      const char *key;
+      pair_cache_key_t key = { rev, 0};
 
       SVN_ERR(read_revprop_generation(&generation, fs, pool));
 
-      key = svn_fs_fs__combine_two_numbers(rev, generation, pool);
+      key.second = generation;
       SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
-                             ffd->revprop_cache, key, pool));
+                             ffd->revprop_cache, &key, pool));
       if (is_cached)
         return SVN_NO_ERROR;
     }
@@ -4364,7 +4489,7 @@ struct rep_read_baton
 
   /* The key for the fulltext cache for this rep, if there is a
      fulltext cache. */
-  const char *fulltext_cache_key;
+  pair_cache_key_t fulltext_cache_key;
   /* The text we've been reading, if we're going to cache it. */
   svn_stringbuf_t *current_fulltext;
 
@@ -4555,17 +4680,21 @@ 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.  */
+   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.  */
 static svn_error_t *
 build_rep_list(apr_array_header_t **list,
                svn_stringbuf_t **window_p,
                struct rep_state **src_state,
+               svn_filesize_t *expanded_size,
                svn_fs_t *fs,
                representation_t *first_rep,
                apr_pool_t *pool)
 {
   representation_t rep;
-  struct rep_state *rs;
+  struct rep_state *rs = NULL;
   struct rep_args *rep_args;
   svn_boolean_t is_cached = FALSE;
   apr_file_t *last_file = NULL;
@@ -4574,10 +4703,31 @@ build_rep_list(apr_array_header_t **list
   *list = apr_array_make(pool, 1, sizeof(struct rep_state *));
   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_args, &last_file,
+                           &last_revision, &rep, fs, pool));
+
+  /* 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_args->is_delta || first_rep->size != 4)
+      *expanded_size = first_rep->size;
+
   while (1)
     {
-      SVN_ERR(create_rep_state(&rs, &rep_args, &last_file,
-                               &last_revision, &rep, fs, pool));
+      /* fetch state, if that has not been done already */
+      if (!rs)
+        SVN_ERR(create_rep_state(&rs, &rep_args, &last_file,
+                                &last_revision, &rep, fs, pool));
+
       SVN_ERR(get_cached_combined_window(window_p, rs, &is_cached, pool));
       if (is_cached)
         {
@@ -4608,6 +4758,8 @@ build_rep_list(apr_array_header_t **list
       rep.offset = rep_args->base_offset;
       rep.size = rep_args->base_length;
       rep.txn_id = NULL;
+
+      rs = NULL;
     }
 }
 
@@ -4621,7 +4773,7 @@ static svn_error_t *
 rep_read_get_baton(struct rep_read_baton **rb_p,
                    svn_fs_t *fs,
                    representation_t *rep,
-                   const char *fulltext_cache_key,
+                   pair_cache_key_t fulltext_cache_key,
                    apr_pool_t *pool)
 {
   struct rep_read_baton *b;
@@ -4634,23 +4786,23 @@ rep_read_get_baton(struct rep_read_baton
   b->md5_checksum_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
   b->checksum_finalized = FALSE;
   b->md5_checksum = svn_checksum_dup(rep->md5_checksum, pool);
-  b->len = rep->expanded_size ? rep->expanded_size : rep->size;
+  b->len = rep->expanded_size;
   b->off = 0;
   b->fulltext_cache_key = fulltext_cache_key;
   b->pool = svn_pool_create(pool);
   b->filehandle_pool = svn_pool_create(pool);
 
-  if (fulltext_cache_key)
+  SVN_ERR(build_rep_list(&b->rs_list, &b->base_window,
+                         &b->src_state, &b->len, fs, rep,
+                         b->filehandle_pool));
+
+  if (SVN_IS_VALID_REVNUM(fulltext_cache_key.revision))
     b->current_fulltext = svn_stringbuf_create_ensure
                             ((apr_size_t)b->len,
                              b->filehandle_pool);
   else
     b->current_fulltext = NULL;
 
-  SVN_ERR(build_rep_list(&b->rs_list, &b->base_window,
-                         &b->src_state, fs, rep,
-                         b->filehandle_pool));
-
   /* Save our output baton. */
   *rb_p = b;
 
@@ -4827,8 +4979,8 @@ get_contents(struct rep_read_baton *rb,
           offset = rs->off - rs->start;
           if (copy_len + offset > rb->base_window->len)
             copy_len = offset < rb->base_window->len
-                     ? rb->base_window->len - offset
-                     : 0;
+                     ? (apr_size_t)(rb->base_window->len - offset)
+                     : 0ul;
 
           memcpy (cur, rb->base_window->data + offset, copy_len);
         }
@@ -4935,7 +5087,7 @@ rep_read_contents(void *baton,
   if (rb->off == rb->len && rb->current_fulltext)
     {
       fs_fs_data_t *ffd = rb->fs->fsap_data;
-      SVN_ERR(svn_cache__set(ffd->fulltext_cache, rb->fulltext_cache_key,
+      SVN_ERR(svn_cache__set(ffd->fulltext_cache, &rb->fulltext_cache_key,
                              rb->current_fulltext, rb->pool));
       rb->current_fulltext = NULL;
     }
@@ -4966,7 +5118,7 @@ read_representation(svn_stream_t **conte
   else
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      const char *fulltext_cache_key = NULL;
+      pair_cache_key_t fulltext_cache_key = {rep->revision, rep->offset};
       svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
       struct rep_read_baton *rb;
 
@@ -4975,11 +5127,8 @@ read_representation(svn_stream_t **conte
         {
           svn_stringbuf_t *fulltext;
           svn_boolean_t is_cached;
-          fulltext_cache_key = svn_fs_fs__combine_two_numbers(rep->revision,
-                                                              rep->offset,
-                                                              pool);
           SVN_ERR(svn_cache__get((void **) &fulltext, &is_cached,
-                                 ffd->fulltext_cache, fulltext_cache_key,
+                                 ffd->fulltext_cache, &fulltext_cache_key,
                                  pool));
           if (is_cached)
             {
@@ -4987,6 +5136,8 @@ read_representation(svn_stream_t **conte
               return SVN_NO_ERROR;
             }
         }
+      else
+        fulltext_cache_key.revision = SVN_INVALID_REVNUM;
 
       SVN_ERR(rep_read_get_baton(&rb, fs, rep, fulltext_cache_key, pool));
 
@@ -5095,6 +5246,70 @@ svn_fs_fs__get_file_delta_stream(svn_txd
   return SVN_NO_ERROR;
 }
 
+/* Baton for cache_access_wrapper. Wraps the original parameters of
+ * svn_fs_fs__try_process_file_content().
+ */
+typedef struct cache_access_wrapper_baton_t
+{
+  svn_fs_process_contents_func_t func;
+  void* baton;
+} cache_access_wrapper_baton_t;
+
+/* Wrapper to translate between svn_fs_process_contents_func_t and
+ * svn_cache__partial_getter_func_t.
+ */
+static svn_error_t *
+cache_access_wrapper(void **out,
+                     const void *data,
+                     apr_size_t data_len,
+                     void *baton,
+                     apr_pool_t *pool)
+{
+  cache_access_wrapper_baton_t *wrapper_baton = baton;
+
+  SVN_ERR(wrapper_baton->func((const unsigned char *)data,
+                              data_len - 1, /* cache adds terminating 0 */
+                              wrapper_baton->baton,
+                              pool));
+  
+  /* non-NULL value to signal the calling cache that all went well */
+  *out = baton;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__try_process_file_contents(svn_boolean_t *success,
+                                     svn_fs_t *fs,
+                                     node_revision_t *noderev,
+                                     svn_fs_process_contents_func_t processor,
+                                     void* baton,
+                                     apr_pool_t *pool)
+{
+  representation_t *rep = noderev->data_rep;
+  if (rep)
+    {
+      fs_fs_data_t *ffd = fs->fsap_data;
+      pair_cache_key_t fulltext_cache_key = {rep->revision, rep->offset};
+
+      if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
+          && fulltext_size_is_cachable(ffd, rep->expanded_size))
+        {
+          cache_access_wrapper_baton_t wrapper_baton = {processor, baton};
+          void *dummy = NULL;
+
+          return svn_cache__get_partial(&dummy, success,
+                                        ffd->fulltext_cache,
+                                        &fulltext_cache_key,
+                                        cache_access_wrapper,
+                                        &wrapper_baton,
+                                        pool);
+        }
+    }
+
+  *success = FALSE;
+  return SVN_NO_ERROR;
+}
 
 /* Fetch the contents of a directory into ENTRIES.  Values are stored
    as filename to string mappings; further conversion is necessary to
@@ -5127,8 +5342,8 @@ get_dir_contents(apr_hash_t *entries,
        */
       apr_pool_t *text_pool = svn_pool_create(pool);
       apr_size_t len = noderev->data_rep->expanded_size
-                     ? noderev->data_rep->expanded_size
-                     : noderev->data_rep->size;
+                     ? (apr_size_t)noderev->data_rep->expanded_size
+                     : (apr_size_t)noderev->data_rep->size;
       svn_stringbuf_t *text = svn_stringbuf_create_ensure(len, text_pool);
       text->len = len;
 
@@ -5365,11 +5580,10 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
   apr_hash_t *proplist;
   svn_stream_t *stream;
 
-  proplist = apr_hash_make(pool);
-
   if (noderev->prop_rep && noderev->prop_rep->txn_id)
     {
       const char *filename = 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));
@@ -5377,9 +5591,31 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
     }
   else if (noderev->prop_rep)
     {
+      fs_fs_data_t *ffd = fs->fsap_data;
+      representation_t *rep = noderev->prop_rep;
+      
+      pair_cache_key_t key = { rep->revision, rep->offset };
+      if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
+        {
+          svn_boolean_t is_cached;
+          SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
+                                 ffd->properties_cache, &key, pool));
+          if (is_cached)
+            return SVN_NO_ERROR;
+        }
+
+      proplist = apr_hash_make(pool);
       SVN_ERR(read_representation(&stream, fs, noderev->prop_rep, pool));
       SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
       SVN_ERR(svn_stream_close(stream));
+      
+      if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
+        SVN_ERR(svn_cache__set(ffd->properties_cache, &key, proplist, pool));
+    }
+  else
+    {
+      /* return an empty prop list if the node doesn't have any props */
+      proplist = apr_hash_make(pool);
     }
 
   *proplist_p = proplist;
@@ -5484,8 +5720,9 @@ fold_change(apr_hash_t *changes,
   apr_pool_t *pool = apr_hash_pool_get(changes);
   svn_fs_path_change2_t *old_change, *new_change;
   const char *path;
+  apr_size_t path_len = strlen(change->path);
 
-  if ((old_change = apr_hash_get(changes, change->path, APR_HASH_KEY_STRING)))
+  if ((old_change = apr_hash_get(changes, change->path, path_len)))
     {
       /* This path already exists in the hash, so we have to merge
          this change into the already existing one. */
@@ -5623,8 +5860,8 @@ fold_change(apr_hash_t *changes,
      re-use its value, but there is no way to fetch it. The API makes no
      guarantees that this (new) key will not be retained. Thus, we (again)
      copy the key into the target pool to ensure a proper lifetime.  */
-  path = apr_pstrdup(pool, change->path);
-  apr_hash_set(changes, path, APR_HASH_KEY_STRING, new_change);
+  path = apr_pstrmemdup(pool, change->path, path_len);
+  apr_hash_set(changes, path, path_len, new_change);
 
   /* Update the copyfrom cache, if any. */
   if (copyfrom_cache)
@@ -5642,10 +5879,12 @@ fold_change(apr_hash_t *changes,
         }
       /* We need to allocate a copy of the key in the copyfrom_pool if
        * we're not doing a deletion and if it isn't already there. */
-      if (copyfrom_string && ! apr_hash_get(copyfrom_cache, copyfrom_key,
-                                            APR_HASH_KEY_STRING))
-        copyfrom_key = apr_pstrdup(copyfrom_pool, copyfrom_key);
-      apr_hash_set(copyfrom_cache, copyfrom_key, APR_HASH_KEY_STRING,
+      if (   copyfrom_string
+          && (   ! apr_hash_count(copyfrom_cache)
+              || ! apr_hash_get(copyfrom_cache, copyfrom_key, path_len)))
+        copyfrom_key = apr_pstrmemdup(copyfrom_pool, copyfrom_key, path_len);
+
+      apr_hash_set(copyfrom_cache, copyfrom_key, path_len,
                    copyfrom_string);
     }
 
@@ -6019,7 +6258,7 @@ svn_fs_fs__paths_changed(apr_hash_t **ch
 
   SVN_ERR(get_changes(&changes, fs, rev, scratch_pool));
 
-  changed_paths = apr_hash_make(pool);
+  changed_paths = svn_hash__make(pool);
 
   SVN_ERR(process_changes(changed_paths, copyfrom_cache, changes,
                           TRUE, pool));
@@ -6532,25 +6771,20 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
   if (!rep || !rep->txn_id)
     {
       const char *unique_suffix;
+      apr_hash_t *entries;
 
-      {
-        apr_hash_t *entries;
-
-        svn_pool_clear(subpool);
-
-        /* Before we can modify the directory, we need to dump its old
-           contents into a mutable representation file. */
-        SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, parent_noderev,
-                                            subpool));
-        SVN_ERR(unparse_dir_entries(&entries, entries, subpool));
-        SVN_ERR(svn_io_file_open(&file, filename,
-                                 APR_WRITE | APR_CREATE | APR_BUFFERED,
-                                 APR_OS_DEFAULT, pool));
-        out = svn_stream_from_aprfile2(file, TRUE, pool);
-        SVN_ERR(svn_hash_write2(entries, out, SVN_HASH_TERMINATOR, subpool));
+      /* Before we can modify the directory, we need to dump its old
+         contents into a mutable representation file. */
+      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, parent_noderev,
+                                          subpool));
+      SVN_ERR(unparse_dir_entries(&entries, entries, subpool));
+      SVN_ERR(svn_io_file_open(&file, filename,
+                               APR_WRITE | APR_CREATE | APR_BUFFERED,
+                               APR_OS_DEFAULT, pool));
+      out = svn_stream_from_aprfile2(file, TRUE, pool);
+      SVN_ERR(svn_hash_write2(entries, out, SVN_HASH_TERMINATOR, subpool));
 
-        svn_pool_clear(subpool);
-      }
+      svn_pool_clear(subpool);
 
       /* Mark the node-rev's data rep as mutable. */
       rep = apr_pcalloc(pool, sizeof(*rep));
@@ -6571,7 +6805,6 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
     }
 
   /* if we have a directory cache for this transaction, update it */
-  svn_pool_clear(subpool);
   if (ffd->txn_dir_cache)
     {
       /* build parameters: (name, new entry) pair */
@@ -6986,6 +7219,30 @@ get_shared_rep(representation_t **old_re
         }
     }
 
+  /* look for intra-revision matches (usually data reps but not limited
+     to them in case props happen to look like some data rep)
+   */
+  if (*old_rep == NULL && rep->txn_id)
+    {
+      svn_node_kind_t kind;
+      const char *file_name
+        = svn_dirent_join(path_txn_dir(fs, rep->txn_id, pool),
+                          svn_checksum_to_cstring(rep->sha1_checksum, pool),
+                          pool);
+
+      /* in our txn, is there a rep file named with the wanted SHA1?
+         If so, read it and use that rep.
+       */
+      SVN_ERR(svn_io_check_path(file_name, &kind, pool));
+      if (kind == svn_node_file)
+        {
+          svn_stringbuf_t *rep_string;
+          SVN_ERR(svn_stringbuf_from_file2(&rep_string, file_name, pool));
+          SVN_ERR(read_rep_offsets_body(old_rep, rep_string->data,
+                                        rep->txn_id, FALSE, pool));
+        }
+    }
+
   /* Add information that is missing in the cached data. */
   if (*old_rep)
     {
@@ -9553,7 +9810,7 @@ pack_revprops_shard(const char *pack_fil
           total_size + SVN_INT64_BUFFER_SIZE + finfo.size > max_pack_size)
         {
           SVN_ERR(copy_revprops(pack_file_dir, pack_filename, shard_path,
-                                start_rev, rev-1, sizes, total_size,
+                                start_rev, rev-1, sizes, (apr_size_t)total_size,
                                 compression_level, cancel_func, cancel_baton,
                                 iterpool));
 
@@ -9579,7 +9836,7 @@ pack_revprops_shard(const char *pack_fil
   /* write the last pack file */
   if (sizes->nelts != 0)
     SVN_ERR(copy_revprops(pack_file_dir, pack_filename, shard_path,
-                          start_rev, rev-1, sizes, total_size,
+                          start_rev, rev-1, sizes, (apr_size_t)total_size,
                           compression_level, cancel_func, cancel_baton,
                           iterpool));
 
@@ -10166,6 +10423,7 @@ hotcopy_copy_packed_shard(svn_revnum_t *
   const char *src_subdir_packed_shard;
   svn_revnum_t revprop_rev;
   apr_pool_t *iterpool;
+  fs_fs_data_t *src_ffd = src_fs->fsap_data;
 
   /* Copy the packed shard. */
   src_subdir = svn_dirent_join(src_fs->path, PATH_REVS_DIR, scratch_pool);
@@ -10183,18 +10441,43 @@ hotcopy_copy_packed_shard(svn_revnum_t *
   /* Copy revprops belonging to revisions in this pack. */
   src_subdir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR, scratch_pool);
   dst_subdir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR, scratch_pool);
-  iterpool = svn_pool_create(scratch_pool);
-  for (revprop_rev = rev;
-       revprop_rev < rev + max_files_per_dir;
-       revprop_rev++)
+
+  if (   src_ffd->format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT
+      || src_ffd->min_unpacked_rev < rev + max_files_per_dir)
     {
-      svn_pool_clear(iterpool);
+      /* copy unpacked revprops rev by rev */
+      iterpool = svn_pool_create(scratch_pool);
+      for (revprop_rev = rev;
+           revprop_rev < rev + max_files_per_dir;
+           revprop_rev++)
+        {
+          svn_pool_clear(iterpool);
 
-      SVN_ERR(hotcopy_copy_shard_file(src_subdir, dst_subdir,
-                                      revprop_rev, max_files_per_dir,
-                                      iterpool));
+          SVN_ERR(hotcopy_copy_shard_file(src_subdir, dst_subdir,
+                                          revprop_rev, max_files_per_dir,
+                                          iterpool));
+        }
+      svn_pool_destroy(iterpool);
+    }
+  else
+    {
+      /* revprop for revision 0 will never be packed */
+      if (rev == 0)
+        SVN_ERR(hotcopy_copy_shard_file(src_subdir, dst_subdir,
+                                        0, max_files_per_dir,
+                                        scratch_pool));
+
+      /* packed revprops folder */
+      packed_shard = apr_psprintf(scratch_pool, "%ld" PATH_EXT_PACKED_SHARD,
+                                  rev / max_files_per_dir);
+      src_subdir_packed_shard = svn_dirent_join(src_subdir, packed_shard,
+                                                scratch_pool);
+      SVN_ERR(hotcopy_io_copy_dir_recursively(src_subdir_packed_shard,
+                                              dst_subdir, packed_shard,
+                                              TRUE /* copy_perms */,
+                                              NULL /* cancel_func */, NULL,
+                                              scratch_pool));
     }
-  svn_pool_destroy(iterpool);
 
   /* If necessary, update the min-unpacked rev file in the hotcopy. */
   if (*dst_min_unpacked_rev < rev + max_files_per_dir)

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/fs_fs.h Tue Oct 30 20:03:28 2012
@@ -150,6 +150,20 @@ svn_error_t *svn_fs_fs__get_contents(svn
                                      node_revision_t *noderev,
                                      apr_pool_t *pool);
 
+/* Attempt to fetch the text representation of node-revision NODEREV as
+   seen in filesystem FS and pass it along with the BATON to the PROCESSOR.
+   Set *SUCCESS only of the data could be provided and the processing
+   had been called.
+   Use POOL for all allocations.
+ */
+svn_error_t *
+svn_fs_fs__try_process_file_contents(svn_boolean_t *success,
+                                     svn_fs_t *fs,
+                                     node_revision_t *noderev,
+                                     svn_fs_process_contents_func_t processor,
+                                     void* baton,
+                                     apr_pool_t *pool);
+
 /* Set *STREAM_P to a delta stream turning the contents of the file SOURCE into
    the contents of the file TARGET, allocated in POOL.
    If SOURCE is null, the empty string will be used. */

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/structure?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/structure Tue Oct 30 20:03:28 2012
@@ -273,12 +273,13 @@ in revprops/0/0.
 
 Pack file format
 
-  Top level: <length><packed container>
+  Top level: <packed container>
 
   We always apply data compression to the pack file - using the
   SVN_DELTA_COMPRESSION_LEVEL_NONE level if compression is disabled.
-  <length> is being encoded using the variable-length svndiff integer
-  format.
+  (Note that compression at SVN_DELTA_COMPRESSION_LEVEL_NONE is not
+  a no-op stream transformation although most of the data will remain
+  human readable.)
 
   container := header '\n' (revprops)+
   header    := start_rev '\n' rev_count '\n' (size '\n')+
@@ -462,7 +463,8 @@ defined:
   props     "<rev> <offset> <length> <size> <digest>" for props rep
             <rev> and <offset> give location of rep
             <length> gives length of rep, sans header and trailer
-            <size> gives size of expanded rep
+            <size> gives size of expanded rep; may be 0 if equal
+             to the length
             <digest> gives hex MD5 digest of expanded rep
             ### in formats >=4, also present:
             <sha1-digest> gives hex SHA1 digest of expanded rep