You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/15 10:52:18 UTC

svn commit: r1532250 [20/37] - in /subversion/branches/cache-server: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/emacs/ contrib/hook-scripts/ contrib/server-side/fsfsfixer/ contrib/se...

Modified: subversion/branches/cache-server/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/dump.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/dump.c Tue Oct 15 08:52:06 2013
@@ -38,6 +38,7 @@
 
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_fs_private.h"
+#include "private/svn_cache.h"
 
 #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
 
@@ -130,6 +131,13 @@ struct edit_baton
   /* reusable buffer for writing file contents */
   char buffer[SVN__STREAM_CHUNK_SIZE];
   apr_size_t bufsize;
+
+  /* map nodeID -> node kind.  May be NULL.
+     The key is the string representation of the node ID given in
+     directory entries.  If we find an entry in this cache, the
+     respective node has already been verified as readable and being
+     of the type stored as value in the cache. */
+  svn_cache__t *verified_dirents_cache;
 };
 
 struct dir_baton
@@ -960,6 +968,7 @@ get_dump_editor(const svn_delta_editor_t
                 svn_revnum_t oldest_dumped_rev,
                 svn_boolean_t use_deltas,
                 svn_boolean_t verify,
+                svn_cache__t *verified_dirents_cache,
                 apr_pool_t *pool)
 {
   /* Allocate an edit baton to be stored in every directory baton.
@@ -984,6 +993,7 @@ get_dump_editor(const svn_delta_editor_t
   eb->verify = verify;
   eb->found_old_reference = found_old_reference;
   eb->found_old_mergeinfo = found_old_mergeinfo;
+  eb->verified_dirents_cache = verified_dirents_cache;
 
   /* Set up the editor. */
   dump_editor->open_root = open_root;
@@ -1097,7 +1107,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
 {
   const svn_delta_editor_t *dump_editor;
   void *dump_edit_baton = NULL;
-  svn_revnum_t i;
+  svn_revnum_t rev;
   svn_fs_t *fs = svn_repos_fs(repos);
   apr_pool_t *subpool = svn_pool_create(pool);
   svn_revnum_t youngest;
@@ -1129,10 +1139,6 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                              _("End revision %ld is invalid "
                                "(youngest revision is %ld)"),
                              end_rev, youngest);
-  if ((start_rev == 0) && incremental)
-    incremental = FALSE; /* revision 0 looks the same regardless of
-                            whether or not this is an incremental
-                            dump, so just simplify things. */
 
   /* Write out the UUID. */
   SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));
@@ -1156,10 +1162,9 @@ svn_repos_dump_fs3(svn_repos_t *repos,
     notify = svn_repos_notify_create(svn_repos_notify_dump_rev_end,
                                      pool);
 
-  /* Main loop:  we're going to dump revision i.  */
-  for (i = start_rev; i <= end_rev; i++)
+  /* Main loop:  we're going to dump revision REV.  */
+  for (rev = start_rev; rev <= end_rev; rev++)
     {
-      svn_revnum_t from_rev, to_rev;
       svn_fs_root_t *to_root;
       svn_boolean_t use_deltas_for_rev;
 
@@ -1169,56 +1174,36 @@ svn_repos_dump_fs3(svn_repos_t *repos,
       if (cancel_func)
         SVN_ERR(cancel_func(cancel_baton));
 
-      /* Special-case the initial revision dump: it needs to contain
-         *all* nodes, because it's the foundation of all future
-         revisions in the dumpfile. */
-      if ((i == start_rev) && (! incremental))
-        {
-          /* Special-special-case a dump of revision 0. */
-          if (i == 0)
-            {
-              /* Just write out the one revision 0 record and move on.
-                 The parser might want to use its properties. */
-              SVN_ERR(write_revision_record(stream, fs, 0, subpool));
-              to_rev = 0;
-              goto loop_end;
-            }
-
-          /* Compare START_REV to revision 0, so that everything
-             appears to be added.  */
-          from_rev = 0;
-          to_rev = i;
-        }
-      else
-        {
-          /* In the normal case, we want to compare consecutive revs. */
-          from_rev = i - 1;
-          to_rev = i;
-        }
-
       /* Write the revision record. */
-      SVN_ERR(write_revision_record(stream, fs, to_rev, subpool));
+      SVN_ERR(write_revision_record(stream, fs, rev, subpool));
+
+      /* When dumping revision 0, we just write out the revision record.
+         The parser might want to use its properties. */
+      if (rev == 0)
+        goto loop_end;
 
       /* Fetch the editor which dumps nodes to a file.  Regardless of
          what we've been told, don't use deltas for the first rev of a
          non-incremental dump. */
-      use_deltas_for_rev = use_deltas && (incremental || i != start_rev);
-      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev,
+      use_deltas_for_rev = use_deltas && (incremental || rev != start_rev);
+      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, rev,
                               "", stream, &found_old_reference,
                               &found_old_mergeinfo, NULL,
                               notify_func, notify_baton,
-                              start_rev, use_deltas_for_rev, FALSE, subpool));
+                              start_rev, use_deltas_for_rev, FALSE,
+                              NULL, subpool));
 
       /* Drive the editor in one way or another. */
-      SVN_ERR(svn_fs_revision_root(&to_root, fs, to_rev, subpool));
+      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
 
       /* If this is the first revision of a non-incremental dump,
          we're in for a full tree dump.  Otherwise, we want to simply
          replay the revision.  */
-      if ((i == start_rev) && (! incremental))
+      if ((rev == start_rev) && (! incremental))
         {
+          /* Compare against revision 0, so everything appears to be added. */
           svn_fs_root_t *from_root;
-          SVN_ERR(svn_fs_revision_root(&from_root, fs, from_rev, subpool));
+          SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, subpool));
           SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
                                        to_root, "",
                                        dump_editor, dump_edit_baton,
@@ -1232,6 +1217,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
         }
       else
         {
+          /* The normal case: compare consecutive revs. */
           SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                     dump_editor, dump_edit_baton,
                                     NULL, NULL, subpool));
@@ -1244,7 +1230,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
     loop_end:
       if (notify_func)
         {
-          notify->revision = to_rev;
+          notify->revision = rev;
           notify_func(notify_baton, notify, subpool);
         }
     }
@@ -1317,9 +1303,42 @@ verify_directory_entry(void *baton, cons
 {
   struct dir_baton *db = baton;
   svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
-  char *path = svn_relpath_join(db->path, (const char *)key, pool);
+  char *path;
   apr_hash_t *dirents;
   svn_filesize_t len;
+  svn_string_t *unparsed_id;
+
+  /* most directory entries will be unchanged from previous revs.
+     We should find those in the cache and they must match the
+     type defined in the DIRENT. */
+  if (db->edit_baton->verified_dirents_cache)
+    {
+      svn_node_kind_t kind;
+      svn_boolean_t found;
+      unparsed_id = svn_fs_unparse_id(dirent->id, pool);
+
+      SVN_ERR(svn_cache__get((void **)&kind, &found,
+                             db->edit_baton->verified_dirents_cache,
+                             unparsed_id->data, pool));
+
+      if (found)
+        {
+          if (kind == dirent->kind)
+            return SVN_NO_ERROR;
+          else
+            {
+              path = svn_relpath_join(db->path, (const char *)key, pool);
+
+              return
+                  svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                                    _("Unexpected node kind %d for '%s'. "
+                                      "Expected kind was %d."),
+                                    dirent->kind, path, kind);
+            }
+        }
+    }
+
+  path = svn_relpath_join(db->path, (const char *)key, pool);
 
   /* since we can't access the directory entries directly by their ID,
      we need to navigate from the FS_ROOT to them (relatively expensive
@@ -1341,6 +1360,11 @@ verify_directory_entry(void *baton, cons
                              dirent->kind, path);
   }
 
+  /* remember ID, kind pair */
+  if (db->edit_baton->verified_dirents_cache)
+    SVN_ERR(svn_cache__set(db->edit_baton->verified_dirents_cache,
+                           unparsed_id->data, &dirent->kind, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -1357,6 +1381,74 @@ verify_close_directory(void *dir_baton,
   return close_directory(dir_baton, pool);
 }
 
+static void
+notify_verification_error(svn_revnum_t rev,
+                          svn_error_t *err,
+                          svn_repos_notify_func_t notify_func,
+                          void *notify_baton,
+                          apr_pool_t *pool)
+{
+  svn_repos_notify_t *notify_failure;
+
+  if (notify_func == NULL)
+    return;
+
+  notify_failure = svn_repos_notify_create(svn_repos_notify_failure, pool);
+  notify_failure->err = err;
+  notify_failure->revision = rev;
+  notify_func(notify_baton, notify_failure, pool);
+}
+
+/* Verify revision REV in file system FS. */
+static svn_error_t *
+verify_one_revision(svn_fs_t *fs,
+                    svn_revnum_t rev,
+                    svn_repos_notify_func_t notify_func,
+                    void *notify_baton,
+                    svn_revnum_t start_rev,
+                    svn_cancel_func_t cancel_func,
+                    void *cancel_baton,
+                    svn_cache__t *verified_dirents_cache,
+                    apr_pool_t *scratch_pool)
+{
+  const svn_delta_editor_t *dump_editor;
+  void *dump_edit_baton;
+  svn_fs_root_t *to_root;
+  apr_hash_t *props;
+  const svn_delta_editor_t *cancel_editor;
+  void *cancel_edit_baton;
+
+  /* Get cancellable dump editor, but with our close_directory handler.*/
+  SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton,
+                          fs, rev, "",
+                          svn_stream_empty(scratch_pool),
+                          NULL, NULL,
+                          verify_close_directory,
+                          notify_func, notify_baton,
+                          start_rev,
+                          FALSE, TRUE, /* use_deltas, verify */
+                          verified_dirents_cache,
+                          scratch_pool));
+  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
+                                            dump_editor, dump_edit_baton,
+                                            &cancel_editor,
+                                            &cancel_edit_baton,
+                                            scratch_pool));
+  SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, scratch_pool));
+  SVN_ERR(svn_fs_verify_root(to_root, scratch_pool));
+  SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
+                            cancel_editor, cancel_edit_baton,
+                            NULL, NULL, scratch_pool));
+ 
+  /* While our editor close_edit implementation is a no-op, we still
+     do this for completeness. */
+  SVN_ERR(cancel_editor->close_edit(cancel_edit_baton, scratch_pool));
+ 
+  SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton type used for forwarding notifications from FS API to REPOS API. */
 struct verify_fs2_notify_func_baton_t
 {
@@ -1383,10 +1475,35 @@ verify_fs2_notify_func(svn_revnum_t revi
                             notify_baton->notify, pool);
 }
 
+/* cache entry (de-)serialization support for svn_node_kind_t. */
+static svn_error_t *
+serialize_node_kind(void **data,
+                    apr_size_t *data_len,
+                    void *in,
+                    apr_pool_t *pool)
+{
+  *data_len = sizeof(svn_node_kind_t);
+  *data = in;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+deserialize_node_kind(void **out,
+                      void *data,
+                      apr_size_t data_len,
+                      apr_pool_t *pool)
+{
+  *(svn_node_kind_t *)out = *(svn_node_kind_t *)data;
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
-svn_repos_verify_fs2(svn_repos_t *repos,
+svn_repos_verify_fs3(svn_repos_t *repos,
                      svn_revnum_t start_rev,
                      svn_revnum_t end_rev,
+                     svn_boolean_t keep_going,
                      svn_repos_notify_func_t notify_func,
                      void *notify_baton,
                      svn_cancel_func_t cancel_func,
@@ -1400,6 +1517,9 @@ svn_repos_verify_fs2(svn_repos_t *repos,
   svn_repos_notify_t *notify;
   svn_fs_progress_notify_func_t verify_notify = NULL;
   struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
+  svn_error_t *err;
+  svn_boolean_t found_corruption = FALSE;
+  svn_cache__t *verified_dirents_cache = NULL;
 
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1428,7 +1548,6 @@ svn_repos_verify_fs2(svn_repos_t *repos,
     {
       notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end,
                                        pool);
-
       verify_notify = verify_fs2_notify_func;
       verify_notify_baton = apr_palloc(pool, sizeof(*verify_notify_baton));
       verify_notify_baton->notify_func = notify_func;
@@ -1438,49 +1557,63 @@ svn_repos_verify_fs2(svn_repos_t *repos,
     }
 
   /* Verify global metadata and backend-specific data first. */
-  SVN_ERR(svn_fs_verify(svn_fs_path(fs, pool), svn_fs_config(fs, pool),
-                        start_rev, end_rev,
-                        verify_notify, verify_notify_baton,
-                        cancel_func, cancel_baton, pool));
+  err = svn_fs_verify(svn_fs_path(fs, pool), svn_fs_config(fs, pool),
+                      start_rev, end_rev,
+                      verify_notify, verify_notify_baton,
+                      cancel_func, cancel_baton, pool);
+
+  if (err && !keep_going)
+    {
+      found_corruption = TRUE;
+      notify_verification_error(SVN_INVALID_REVNUM, err, notify_func,
+                                notify_baton, iterpool);
+      svn_error_clear(err);
+      return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+                               _("Repository '%s' failed to verify"),
+                               svn_dirent_local_style(svn_repos_path(repos,
+                                                                     pool),
+                                                      pool));
+    }
+  else
+    {
+      if (err)
+        found_corruption = TRUE;
+      svn_error_clear(err);
+    }
+
+  if (svn_cache__get_global_membuffer_cache())
+    SVN_ERR(svn_cache__create_membuffer_cache
+                                 (&verified_dirents_cache,
+                                  svn_cache__get_global_membuffer_cache(),
+                                  serialize_node_kind,
+                                  deserialize_node_kind,
+                                  APR_HASH_KEY_STRING,
+                                  svn_uuid_generate(pool),
+                                  SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+                                  FALSE,
+                                  pool));
 
   for (rev = start_rev; rev <= end_rev; rev++)
     {
-      const svn_delta_editor_t *dump_editor;
-      void *dump_edit_baton;
-      const svn_delta_editor_t *cancel_editor;
-      void *cancel_edit_baton;
-      svn_fs_root_t *to_root;
-      apr_hash_t *props;
-
       svn_pool_clear(iterpool);
 
-      /* Get cancellable dump editor, but with our close_directory handler. */
-      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton,
-                              fs, rev, "",
-                              svn_stream_empty(iterpool),
-                              NULL, NULL,
-                              verify_close_directory,
-                              notify_func, notify_baton,
-                              start_rev,
-                              FALSE, TRUE, /* use_deltas, verify */
-                              iterpool));
-      SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
-                                                dump_editor, dump_edit_baton,
-                                                &cancel_editor,
-                                                &cancel_edit_baton,
-                                                iterpool));
-
-      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
-      SVN_ERR(svn_fs_verify_root(to_root, iterpool));
-
-      SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
-                                cancel_editor, cancel_edit_baton,
-                                NULL, NULL, iterpool));
-      /* While our editor close_edit implementation is a no-op, we still
-         do this for completeness. */
-      SVN_ERR(cancel_editor->close_edit(cancel_edit_baton, iterpool));
+      /* Wrapper function to catch the possible errors. */
+      err = verify_one_revision(fs, rev, notify_func, notify_baton,
+                                start_rev, cancel_func, cancel_baton,
+                                verified_dirents_cache, iterpool);
 
-      SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool));
+      if (err)
+        {
+          found_corruption = TRUE;
+          notify_verification_error(rev, err, notify_func, notify_baton,
+                                    iterpool);
+          svn_error_clear(err);
+
+          if (keep_going)
+            continue;
+          else
+            break;
+        }
 
       if (notify_func)
         {
@@ -1499,5 +1632,12 @@ svn_repos_verify_fs2(svn_repos_t *repos,
   /* Per-backend verification. */
   svn_pool_destroy(iterpool);
 
+  if (found_corruption)
+    return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+                             _("Repository '%s' failed to verify"),
+                             svn_dirent_local_style(svn_repos_path(repos,
+                                                                   pool),
+                                                    pool));
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/cache-server/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/fs-wrap.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/fs-wrap.c Tue Oct 15 08:52:06 2013
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <ctype.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_pools.h"
 #include "svn_error.h"
@@ -34,7 +35,7 @@
 #include "svn_time.h"
 #include "svn_sorts.h"
 #include "repos.h"
-#include "svn_private_config.h"
+
 #include "private/svn_repos_private.h"
 #include "private/svn_utf_private.h"
 #include "private/svn_fspath.h"
@@ -172,6 +173,10 @@ svn_repos__validate_prop(const char *nam
 {
   svn_prop_kind_t kind = svn_property_kind2(name);
 
+  /* Allow deleting any property, even a property we don't allow to set. */
+  if (value == NULL)
+    return SVN_NO_ERROR;
+
   /* Disallow setting non-regular properties. */
   if (kind != svn_prop_regular_kind)
     return svn_error_createf
@@ -409,10 +414,8 @@ svn_repos_fs_revision_prop(svn_string_t 
   else if (readability == svn_repos_revision_access_partial)
     {
       /* Only svn:author and svn:date are fetchable. */
-      if ((strncmp(propname, SVN_PROP_REVISION_AUTHOR,
-                   sizeof(SVN_PROP_REVISION_AUTHOR)-1) != 0)
-          && (strncmp(propname, SVN_PROP_REVISION_DATE,
-                      sizeof(SVN_PROP_REVISION_DATE)-1) != 0))
+      if ((strcmp(propname, SVN_PROP_REVISION_AUTHOR) != 0)
+          && (strcmp(propname, SVN_PROP_REVISION_DATE) != 0))
         *value_p = NULL;
 
       else

Modified: subversion/branches/cache-server/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/hooks.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/hooks.c Tue Oct 15 08:52:06 2013
@@ -27,6 +27,7 @@
 #include <apr_pools.h>
 #include <apr_file_io.h>
 
+#include "svn_private_config.h"
 #include "svn_config.h"
 #include "svn_hash.h"
 #include "svn_error.h"
@@ -36,7 +37,7 @@
 #include "svn_repos.h"
 #include "svn_utf.h"
 #include "repos.h"
-#include "svn_private_config.h"
+
 #include "private/svn_fs_private.h"
 #include "private/svn_repos_private.h"
 #include "private/svn_string_private.h"

Modified: subversion/branches/cache-server/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/load-fs-vtable.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/load-fs-vtable.c Tue Oct 15 08:52:06 2013
@@ -99,6 +99,9 @@ struct revision_baton
   apr_int32_t rev_offset;
   svn_boolean_t skipped;
 
+  /* Array of svn_prop_t with revision properties. */
+  apr_array_header_t *revprops;
+
   struct parse_baton *pb;
   apr_pool_t *pool;
 };
@@ -448,6 +451,7 @@ make_revision_baton(apr_hash_t *headers,
   rb->pb = pb;
   rb->pool = pool;
   rb->rev = SVN_INVALID_REVNUM;
+  rb->revprops = apr_array_make(rb->pool, 8, sizeof(svn_prop_t));
 
   if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
     {
@@ -698,10 +702,12 @@ set_revision_property(void *baton,
 
   if (rb->rev > 0)
     {
-      if (rb->pb->validate_props)
-        SVN_ERR(svn_repos_fs_change_txn_prop(rb->txn, name, value, rb->pool));
-      else
-        SVN_ERR(svn_fs_change_txn_prop(rb->txn, name, value, rb->pool));
+      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+
+      /* Collect property changes to apply them in one FS call in
+         close_revision. */
+      prop->name = apr_pstrdup(rb->pool, name);
+      prop->value = svn_string_dup(value, rb->pool);
 
       /* Remember any datestamp that passes through!  (See comment in
          close_revision() below.) */
@@ -920,6 +926,21 @@ close_revision(void *baton)
   if (rb->skipped || (rb->rev <= 0))
     return SVN_NO_ERROR;
 
+  if (!rb->datestamp)
+    {
+      /* Remove 'svn:date' revision property that was set by FS layer when TXN
+         created if source dump doesn't have 'svn:date' property. */
+      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+      prop->name = SVN_PROP_REVISION_DATE;
+      prop->value = NULL;
+    }
+
+  /* Apply revision property changes. */
+  if (rb->pb->validate_props)
+    SVN_ERR(svn_repos_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+  else
+    SVN_ERR(svn_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+
   /* Get the txn name and hooks environment if they will be needed. */
   if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
     {
@@ -947,7 +968,8 @@ close_revision(void *baton)
     }
 
   /* Commit. */
-  err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
+  err = svn_fs_commit_txn2(&conflict_msg, &committed_rev, rb->txn, FALSE,
+                           rb->pool);
   if (SVN_IS_VALID_REVNUM(committed_rev))
     {
       if (err)
@@ -1005,15 +1027,6 @@ close_revision(void *baton)
   /* Deltify the predecessors of paths changed in this revision. */
   SVN_ERR(svn_fs_deltify_revision(pb->fs, committed_rev, rb->pool));
 
-  /* Grrr, svn_fs_commit_txn rewrites the datestamp property to the
-     current clock-time.  We don't want that, we want to preserve
-     history exactly.  Good thing revision props aren't versioned!
-     Note that if rb->datestamp is NULL, that's fine -- if the dump
-     data doesn't carry a datestamp, we want to preserve that fact in
-     the load. */
-  SVN_ERR(change_rev_prop(pb->repos, committed_rev, SVN_PROP_REVISION_DATE,
-                          rb->datestamp, pb->validate_props, rb->pool));
-
   if (pb->notify_func)
     {
       pb->notify->action = svn_repos_notify_load_txn_committed;

Modified: subversion/branches/cache-server/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/log.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/log.c Tue Oct 15 08:52:06 2013
@@ -25,8 +25,8 @@
 #define APR_WANT_STRFUNC
 #include <apr_want.h>
 
-#include "svn_compat.h"
 #include "svn_private_config.h"
+#include "svn_compat.h"
 #include "svn_hash.h"
 #include "svn_pools.h"
 #include "svn_error.h"
@@ -69,7 +69,8 @@ svn_repos_check_revision_access(svn_repo
 
   /* Fetch the changes associated with REVISION. */
   SVN_ERR(svn_fs_revision_root(&rev_root, fs, revision, pool));
-  SVN_ERR(svn_fs_paths_changed2(&changes, rev_root, pool));
+  SVN_ERR(svn_fs_paths_changed3(&changes, rev_root,
+                                svn_move_behavior_explicit_moves, pool));
 
   /* No changed paths?  We're done. */
   if (apr_hash_count(changes) == 0)
@@ -105,6 +106,8 @@ svn_repos_check_revision_access(svn_repo
         {
         case svn_fs_path_change_add:
         case svn_fs_path_change_replace:
+        case svn_fs_path_change_move:
+        case svn_fs_path_change_movereplace:
           {
             const char *copyfrom_path;
             svn_revnum_t copyfrom_rev;
@@ -163,7 +166,8 @@ svn_repos_check_revision_access(svn_repo
  *
  * To prevent changes from being processed over and over again, the
  * changed paths for ROOT may be passed in PREFETCHED_CHANGES.  If the
- * latter is NULL, we will request the list inside this function.
+ * latter is NULL, we will request the list inside this function using
+ * the specified MOVE_BEHAVIOR.
  *
  * If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
  * AUTHZ_READ_BATON and FS) to check whether each changed-path (and
@@ -184,6 +188,7 @@ detect_changed(apr_hash_t **changed,
                svn_fs_root_t *root,
                svn_fs_t *fs,
                apr_hash_t *prefetched_changes,
+               svn_move_behavior_t move_behavior,
                svn_repos_authz_func_t authz_read_func,
                void *authz_read_baton,
                apr_pool_t *pool)
@@ -196,7 +201,7 @@ detect_changed(apr_hash_t **changed,
 
   *changed = svn_hash__make(pool);
   if (changes == NULL)
-    SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+    SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
 
   if (apr_hash_count(changes) == 0)
     /* No paths changed in this revision?  Uh, sure, I guess the
@@ -210,19 +215,16 @@ detect_changed(apr_hash_t **changed,
       /* NOTE:  Much of this loop is going to look quite similar to
          svn_repos_check_revision_access(), but we have to do more things
          here, so we'll live with the duplication. */
-      const void *key;
-      void *val;
       svn_fs_path_change2_t *change;
       const char *path;
+      apr_ssize_t path_len;
       char action;
       svn_log_changed_path2_t *item;
 
       svn_pool_clear(subpool);
 
       /* KEY will be the path, VAL the change. */
-      apr_hash_this(hi, &key, NULL, &val);
-      path = (const char *) key;
-      change = val;
+      apr_hash_this(hi, (const void **)&path, &path_len, (void **)&change);
 
       /* Skip path if unreadable. */
       if (authz_read_func)
@@ -258,6 +260,14 @@ detect_changed(apr_hash_t **changed,
           action = 'D';
           break;
 
+        case svn_fs_path_change_move:
+          action = 'V';
+          break;
+
+        case svn_fs_path_change_movereplace:
+          action = 'E';
+          break;
+
         case svn_fs_path_change_modify:
         default:
           action = 'M';
@@ -309,13 +319,18 @@ detect_changed(apr_hash_t **changed,
         }
 
 
-      if ((action == 'A') || (action == 'R'))
+      if (   (action == 'A') || (action == 'R')
+          || (action == 'V') || (action == 'E'))
         {
-          const char *copyfrom_path;
-          svn_revnum_t copyfrom_rev;
+          const char *copyfrom_path = change->copyfrom_path;
+          svn_revnum_t copyfrom_rev = change->copyfrom_rev;
 
-          SVN_ERR(svn_fs_copied_from(&copyfrom_rev, &copyfrom_path,
-                                     root, path, subpool));
+          /* the following is a potentially expensive operation since on FSFS
+             we will follow the DAG from ROOT to PATH and that requires
+             actually reading the directories along the way. */
+          if (!change->copyfrom_known)
+            SVN_ERR(svn_fs_copied_from(&copyfrom_rev, &copyfrom_path,
+                                      root, path, subpool));
 
           if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev))
             {
@@ -341,7 +356,9 @@ detect_changed(apr_hash_t **changed,
                 }
             }
         }
-      svn_hash_sets(*changed, apr_pstrdup(pool, path), item);
+
+      apr_hash_set(*changed, apr_pstrmemdup(pool, path, path_len), path_len,
+                   item);
     }
 
   svn_pool_destroy(subpool);
@@ -560,7 +577,9 @@ next_history_rev(const apr_array_header_
    catalogs describing how mergeinfo values on paths (which are the
    keys of those catalogs) were changed in REV.  If *PREFETCHED_CAHNGES
    already contains the changed paths for REV, use that.  Otherwise,
-   request that data and return it in *PREFETCHED_CHANGES. */
+   request that data and return it in *PREFETCHED_CHANGES.
+   MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+   layer which changes to report as moves instead of additions. */
 /* ### TODO: This would make a *great*, useful public function,
    ### svn_repos_fs_mergeinfo_changed()!  -- cmpilato  */
 static svn_error_t *
@@ -569,6 +588,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
                      apr_hash_t **prefetched_changes,
                      svn_fs_t *fs,
                      svn_revnum_t rev,
+                     svn_move_behavior_t move_behavior,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 
@@ -589,7 +609,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
      narrow down our search. */
   SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
   if (*prefetched_changes == NULL)
-    SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
+    SVN_ERR(svn_fs_paths_changed3(prefetched_changes, root, move_behavior,
+                                  scratch_pool));
 
   /* No changed paths?  We're done. */
   if (apr_hash_count(*prefetched_changes) == 0)
@@ -635,6 +656,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
            was.  If not, there's no previous location to examine.  */
         case svn_fs_path_change_add:
         case svn_fs_path_change_replace:
+        case svn_fs_path_change_move:
+        case svn_fs_path_change_movereplace:
           {
             const char *copyfrom_path;
             svn_revnum_t copyfrom_rev;
@@ -779,7 +802,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
    *ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
    If *PREFETCHED_CAHNGES already contains the changed paths for
    REV, use that.  Otherwise, request that data and return it in
-   *PREFETCHED_CHANGES.
+   *PREFETCHED_CHANGES.  MOVE_BEHAVIOR tells the FS layer which
+   changes to report as moves instead of additions.
    Use POOL for all allocations. */
 static svn_error_t *
 get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
@@ -788,6 +812,7 @@ get_combined_mergeinfo_changes(svn_merge
                                svn_fs_t *fs,
                                const apr_array_header_t *paths,
                                svn_revnum_t rev,
+                               svn_move_behavior_t move_behavior,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
@@ -817,7 +842,8 @@ get_combined_mergeinfo_changes(svn_merge
   err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
                              &added_mergeinfo_catalog,
                              prefetched_changes,
-                             fs, rev, scratch_pool, scratch_pool);
+                             fs, rev, move_behavior,
+                             scratch_pool, scratch_pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -834,6 +860,11 @@ get_combined_mergeinfo_changes(svn_merge
         }
     }
 
+  /* In most revisions, there will be no mergeinfo change at all. */
+  if (   apr_hash_count(deleted_mergeinfo_catalog) == 0
+      && apr_hash_count(added_mergeinfo_catalog) == 0)
+    return SVN_NO_ERROR;
+  
   /* Check our PATHS for any changes to their inherited mergeinfo.
      (We deal with changes to mergeinfo directly *on* the paths in the
      following loop.)  */
@@ -1017,6 +1048,7 @@ fill_log_entry(svn_log_entry_t *log_entr
                svn_fs_t *fs,
                apr_hash_t *prefetched_changes,
                svn_boolean_t discover_changed_paths,
+               svn_move_behavior_t move_behavior,
                const apr_array_header_t *revprops,
                svn_repos_authz_func_t authz_read_func,
                void *authz_read_baton,
@@ -1035,7 +1067,7 @@ fill_log_entry(svn_log_entry_t *log_entr
 
       SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
       patherr = detect_changed(&changed_paths,
-                               newroot, fs, prefetched_changes,
+                               newroot, fs, prefetched_changes, move_behavior,
                                authz_read_func, authz_read_baton,
                                pool);
 
@@ -1087,21 +1119,47 @@ fill_log_entry(svn_log_entry_t *log_entr
         }
       else
         {
-          /* Requested only some revprops... */
           int i;
-          for (i = 0; i < revprops->nelts; i++)
+
+          /* Requested only some revprops... */
+          
+          /* often only the standard revprops got requested and delivered.
+             In that case, we can simply pass the hash on. */
+          if (revprops->nelts == apr_hash_count(r_props) && !censor_revprops)
             {
-              char *name = APR_ARRAY_IDX(revprops, i, char *);
-              svn_string_t *value = svn_hash_gets(r_props, name);
-              if (censor_revprops
-                  && !(strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0
-                       || strcmp(name, SVN_PROP_REVISION_DATE) == 0))
-                /* ... but we can only return author/date. */
-                continue;
-              if (log_entry->revprops == NULL)
-                log_entry->revprops = svn_hash__make(pool);
-              svn_hash_sets(log_entry->revprops, name, value);
+              log_entry->revprops = r_props;
+              for (i = 0; i < revprops->nelts; i++)
+                {
+                  const svn_string_t *name
+                    = APR_ARRAY_IDX(revprops, i, const svn_string_t *);
+                  if (!apr_hash_get(r_props, name->data, name->len))
+                    {
+                      /* hash does not match list of revprops we want */
+                      log_entry->revprops = NULL;
+                      break;
+                    }
+                }
             }
+
+          /* slow, revprop-by-revprop filtering */
+          if (log_entry->revprops == NULL)
+            for (i = 0; i < revprops->nelts; i++)
+              {
+                const svn_string_t *name
+                  = APR_ARRAY_IDX(revprops, i, const svn_string_t *);
+                svn_string_t *value
+                  = apr_hash_get(r_props, name->data, name->len);
+                if (censor_revprops
+                    && !(strncmp(name->data, SVN_PROP_REVISION_AUTHOR,
+                                 name->len) == 0
+                         || strncmp(name->data, SVN_PROP_REVISION_DATE,
+                                    name->len) == 0))
+                  /* ... but we can only return author/date. */
+                  continue;
+                if (log_entry->revprops == NULL)
+                  log_entry->revprops = svn_hash__make(pool);
+                apr_hash_set(log_entry->revprops, name->data, name->len, value);
+              }
         }
     }
 
@@ -1126,9 +1184,9 @@ fill_log_entry(svn_log_entry_t *log_entr
    only the revision properties named by the (const char *) array elements
    (i.e. retrieve none if the array is empty).
 
-   LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, and
-   NESTED_MERGES are as per the arguments of the same name to DO_LOGS.  If
-   HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
+   LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, MOVE_BEHAVIOR,
+   and NESTED_MERGES are as per the arguments of the same name to DO_LOGS.
+   If HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
    already represented in LOG_TARGET_HISTORY_AS_MERGEINFO, then don't send
    the log message for REV.  If SUBTRACTIVE_MERGE is true, then REV was
    reverse merged.
@@ -1146,6 +1204,7 @@ send_log(svn_revnum_t rev,
          svn_boolean_t discover_changed_paths,
          svn_boolean_t subtractive_merge,
          svn_boolean_t handling_merged_revision,
+         svn_move_behavior_t move_behavior,
          const apr_array_header_t *revprops,
          svn_boolean_t has_children,
          svn_log_entry_receiver_t receiver,
@@ -1161,8 +1220,8 @@ send_log(svn_revnum_t rev,
   log_entry = svn_log_entry_create(pool);
   SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
                          discover_changed_paths || handling_merged_revision,
-                         revprops, authz_read_func, authz_read_baton,
-                         pool));
+                         move_behavior, revprops, 
+                         authz_read_func, authz_read_baton, pool));
   log_entry->has_children = has_children;
   log_entry->subtractive_merge = subtractive_merge;
 
@@ -1175,32 +1234,33 @@ send_log(svn_revnum_t rev,
       && apr_hash_count(log_target_history_as_mergeinfo))
     {
       apr_hash_index_t *hi;
-      apr_pool_t *subpool = svn_pool_create(pool);
+      apr_pool_t *iterpool = svn_pool_create(pool);
 
       /* REV was merged in, but it might already be part of the log target's
          natural history, so change our starting assumption. */
       found_rev_of_interest = FALSE;
 
       /* Look at each changed path in REV. */
-      for (hi = apr_hash_first(subpool, log_entry->changed_paths2);
+      for (hi = apr_hash_first(pool, log_entry->changed_paths2);
            hi;
            hi = apr_hash_next(hi))
         {
           svn_boolean_t path_is_in_history = FALSE;
           const char *changed_path = svn__apr_hash_index_key(hi);
           apr_hash_index_t *hi2;
-          apr_pool_t *inner_subpool = svn_pool_create(subpool);
+
+          apr_hash_this(hi, (const void**)&changed_path, NULL, NULL);
 
           /* Look at each path on the log target's mergeinfo. */
-          for (hi2 = apr_hash_first(inner_subpool,
+          for (hi2 = apr_hash_first(iterpool,
                                     log_target_history_as_mergeinfo);
                hi2;
                hi2 = apr_hash_next(hi2))
             {
-              const char *mergeinfo_path =
-                svn__apr_hash_index_key(hi2);
-              svn_rangelist_t *rangelist =
-                svn__apr_hash_index_val(hi2);
+              const char *mergeinfo_path;
+              svn_rangelist_t *rangelist;
+              apr_hash_this(hi2, (const void**)&mergeinfo_path, NULL,
+                                 (void **)&rangelist);
 
               /* Check whether CHANGED_PATH at revision REV is a child of
                  a (path, revision) tuple in LOG_TARGET_HISTORY_AS_MERGEINFO. */
@@ -1223,7 +1283,7 @@ send_log(svn_revnum_t rev,
               if (path_is_in_history)
                 break;
             }
-          svn_pool_destroy(inner_subpool);
+          svn_pool_clear(iterpool);
 
           if (!path_is_in_history)
             {
@@ -1234,7 +1294,7 @@ send_log(svn_revnum_t rev,
               break;
             }
         }
-      svn_pool_destroy(subpool);
+      svn_pool_destroy(iterpool);
     }
 
   /* If we only got changed paths the sake of detecting redundant merged
@@ -1628,6 +1688,7 @@ do_logs(svn_fs_t *fs,
         svn_boolean_t handling_merged_revisions,
         svn_boolean_t subtractive_merge,
         svn_boolean_t ignore_missing_locations,
+        svn_move_behavior_t move_behavior,
         const apr_array_header_t *revprops,
         svn_boolean_t descending_order,
         svn_log_entry_receiver_t receiver,
@@ -1677,6 +1738,7 @@ handle_merged_revisions(svn_revnum_t rev
                         svn_mergeinfo_t deleted_mergeinfo,
                         svn_boolean_t discover_changed_paths,
                         svn_boolean_t strict_node_history,
+                        svn_move_behavior_t move_behavior,
                         const apr_array_header_t *revprops,
                         svn_log_entry_receiver_t receiver,
                         void *receiver_baton,
@@ -1719,7 +1781,7 @@ handle_merged_revisions(svn_revnum_t rev
                       pl_range->range.start, pl_range->range.end, 0,
                       discover_changed_paths, strict_node_history,
                       TRUE, pl_range->reverse_merge, TRUE, TRUE,
-                      revprops, TRUE, receiver, receiver_baton,
+                      move_behavior, revprops, TRUE, receiver, receiver_baton,
                       authz_read_func, authz_read_baton, iterpool));
     }
   svn_pool_destroy(iterpool);
@@ -1853,6 +1915,9 @@ store_search(svn_mergeinfo_t processed,
    If IGNORE_MISSING_LOCATIONS is set, don't treat requests for bogus
    repository locations as fatal -- just ignore them.
 
+   MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+   layer which changes to report as moves instead of additions.
+
    If LOG_TARGET_HISTORY_AS_MERGEINFO is not NULL then it contains mergeinfo
    representing the history of PATHS between HIST_START and HIST_END.
 
@@ -1890,6 +1955,7 @@ do_logs(svn_fs_t *fs,
         svn_boolean_t subtractive_merge,
         svn_boolean_t handling_merged_revisions,
         svn_boolean_t ignore_missing_locations,
+        svn_move_behavior_t move_behavior,
         const apr_array_header_t *revprops,
         svn_boolean_t descending_order,
         svn_log_entry_receiver_t receiver,
@@ -1984,8 +2050,8 @@ do_logs(svn_fs_t *fs,
                                                      &deleted_mergeinfo,
                                                      &changes,
                                                      fs, cur_paths,
-                                                     current, iterpool,
-                                                     iterpool));
+                                                     current, move_behavior,
+                                                     iterpool, iterpool));
               has_children = (apr_hash_count(added_mergeinfo) > 0
                               || apr_hash_count(deleted_mergeinfo) > 0);
             }
@@ -1999,7 +2065,7 @@ do_logs(svn_fs_t *fs,
                                log_target_history_as_mergeinfo, nested_merges,
                                discover_changed_paths,
                                subtractive_merge, handling_merged_revisions,
-                               revprops, has_children,
+                               move_behavior, revprops, has_children,
                                receiver, receiver_baton,
                                authz_read_func, authz_read_baton, iterpool));
 
@@ -2022,6 +2088,7 @@ do_logs(svn_fs_t *fs,
                     added_mergeinfo, deleted_mergeinfo,
                     discover_changed_paths,
                     strict_node_history,
+                    move_behavior,
                     revprops,
                     receiver, receiver_baton,
                     authz_read_func,
@@ -2103,7 +2170,8 @@ do_logs(svn_fs_t *fs,
           SVN_ERR(send_log(current, fs, NULL,
                            log_target_history_as_mergeinfo, nested_merges,
                            discover_changed_paths, subtractive_merge,
-                           handling_merged_revisions, revprops, has_children,
+                           handling_merged_revisions, move_behavior,
+                           revprops, has_children,
                            receiver, receiver_baton, authz_read_func,
                            authz_read_baton, iterpool));
           if (has_children)
@@ -2121,7 +2189,8 @@ do_logs(svn_fs_t *fs,
                                               added_mergeinfo,
                                               deleted_mergeinfo,
                                               discover_changed_paths,
-                                              strict_node_history, revprops,
+                                              strict_node_history,
+                                              move_behavior, revprops,
                                               receiver, receiver_baton,
                                               authz_read_func,
                                               authz_read_baton,
@@ -2223,7 +2292,7 @@ get_paths_history_as_mergeinfo(svn_merge
 }
 
 svn_error_t *
-svn_repos_get_logs4(svn_repos_t *repos,
+svn_repos_get_logs5(svn_repos_t *repos,
                     const apr_array_header_t *paths,
                     svn_revnum_t start,
                     svn_revnum_t end,
@@ -2231,6 +2300,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
                     svn_boolean_t discover_changed_paths,
                     svn_boolean_t strict_node_history,
                     svn_boolean_t include_merged_revisions,
+                    svn_move_behavior_t move_behavior,
                     const apr_array_header_t *revprops,
                     svn_repos_authz_func_t authz_read_func,
                     void *authz_read_baton,
@@ -2243,6 +2313,19 @@ svn_repos_get_logs4(svn_repos_t *repos,
   svn_boolean_t descending_order;
   svn_mergeinfo_t paths_history_mergeinfo = NULL;
 
+  if (revprops)
+    {
+      int i;
+      apr_array_header_t *new_revprops
+        = apr_array_make(pool, revprops->nelts, sizeof(svn_string_t *));
+
+      for (i = 0; i < revprops->nelts; ++i)
+        APR_ARRAY_PUSH(new_revprops, svn_string_t *)
+          = svn_string_create(APR_ARRAY_IDX(revprops, i, const char *), pool);
+
+      revprops = new_revprops;
+    }
+  
   /* Setup log range. */
   SVN_ERR(svn_fs_youngest_rev(&head, fs, pool));
 
@@ -2326,7 +2409,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
             rev = start + i;
           SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
                            discover_changed_paths, FALSE,
-                           FALSE, revprops, FALSE, receiver,
+                           FALSE, move_behavior, revprops, FALSE, receiver,
                            receiver_baton, authz_read_func,
                            authz_read_baton, iterpool));
         }
@@ -2354,7 +2437,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
 
   return do_logs(repos->fs, paths, paths_history_mergeinfo, NULL, NULL, start, end,
                  limit, discover_changed_paths, strict_node_history,
-                 include_merged_revisions, FALSE, FALSE, FALSE, revprops,
+                 include_merged_revisions, FALSE, FALSE, FALSE,
+                 move_behavior, revprops,
                  descending_order, receiver, receiver_baton,
                  authz_read_func, authz_read_baton, pool);
 }

Modified: subversion/branches/cache-server/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/replay.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/replay.c Tue Oct 15 08:52:06 2013
@@ -25,6 +25,7 @@
 
 #include <apr_hash.h>
 
+#include "svn_private_config.h"
 #include "svn_types.h"
 #include "svn_delta.h"
 #include "svn_hash.h"
@@ -35,7 +36,7 @@
 #include "svn_props.h"
 #include "svn_pools.h"
 #include "svn_path.h"
-#include "svn_private_config.h"
+
 #include "private/svn_fspath.h"
 #include "private/svn_repos_private.h"
 #include "private/svn_delta_private.h"
@@ -704,31 +705,45 @@ path_driver_cb_func(void **dir_baton,
       /* Handle property modifications. */
       if (change->prop_mod || downgraded_copy)
         {
-          apr_array_header_t *prop_diffs;
-          apr_hash_t *old_props;
-          apr_hash_t *new_props;
-          int i;
-
-          if (source_root)
-            SVN_ERR(svn_fs_node_proplist(&old_props, source_root,
-                                         source_fspath, pool));
-          else
-            old_props = apr_hash_make(pool);
+          if (cb->compare_root)
+            {
+              apr_array_header_t *prop_diffs;
+              apr_hash_t *old_props;
+              apr_hash_t *new_props;
+              int i;
+
+              if (source_root)
+                SVN_ERR(svn_fs_node_proplist(&old_props, source_root,
+                                             source_fspath, pool));
+              else
+                old_props = apr_hash_make(pool);
 
-          SVN_ERR(svn_fs_node_proplist(&new_props, root, edit_path, pool));
+              SVN_ERR(svn_fs_node_proplist(&new_props, root, edit_path, pool));
 
-          SVN_ERR(svn_prop_diffs(&prop_diffs, new_props, old_props,
-                                 pool));
+              SVN_ERR(svn_prop_diffs(&prop_diffs, new_props, old_props,
+                                     pool));
 
-          for (i = 0; i < prop_diffs->nelts; ++i)
+              for (i = 0; i < prop_diffs->nelts; ++i)
+                {
+                  svn_prop_t *pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
+                   if (change->node_kind == svn_node_dir)
+                     SVN_ERR(editor->change_dir_prop(*dir_baton, pc->name,
+                                                     pc->value, pool));
+                   else if (change->node_kind == svn_node_file)
+                     SVN_ERR(editor->change_file_prop(file_baton, pc->name,
+                                                      pc->value, pool));
+                }
+            }
+          else
             {
-              svn_prop_t *pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
-               if (change->node_kind == svn_node_dir)
-                 SVN_ERR(editor->change_dir_prop(*dir_baton, pc->name,
-                                                 pc->value, pool));
-               else if (change->node_kind == svn_node_file)
-                 SVN_ERR(editor->change_file_prop(file_baton, pc->name,
-                                                  pc->value, pool));
+              /* Just do a dummy prop change to signal that there are *any*
+                 propmods. */
+              if (change->node_kind == svn_node_dir)
+                SVN_ERR(editor->change_dir_prop(*dir_baton, "", NULL,
+                                                pool));
+              else if (change->node_kind == svn_node_file)
+                SVN_ERR(editor->change_file_prop(file_baton, "", NULL,
+                                                 pool));
             }
         }
 
@@ -1443,8 +1458,8 @@ replay_node(svn_fs_root_t *root,
             }
 
           SVN_ERR(svn_editor_alter_file(editor, repos_relpath,
-                                        SVN_INVALID_REVNUM, props, checksum,
-                                        contents));
+                                        SVN_INVALID_REVNUM,
+                                        checksum, contents, props));
         }
 
       if (change->node_kind == svn_node_dir

Modified: subversion/branches/cache-server/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/reporter.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/reporter.c Tue Oct 15 08:52:06 2013
@@ -21,6 +21,7 @@
  * ====================================================================
  */
 
+#include "svn_private_config.h"
 #include "svn_dirent_uri.h"
 #include "svn_hash.h"
 #include "svn_path.h"
@@ -32,7 +33,6 @@
 #include "svn_pools.h"
 #include "svn_props.h"
 #include "repos.h"
-#include "svn_private_config.h"
 
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
@@ -499,7 +499,7 @@ get_revision_info(report_baton_t *b,
       info->author = author ? svn_string_dup(author, b->pool) : NULL;
 
       /* Cache it */
-      apr_hash_set(b->revision_infos, &info->rev, sizeof(rev), info);
+      apr_hash_set(b->revision_infos, &info->rev, sizeof(info->rev), info);
     }
 
   *revision_info = info;
@@ -1140,12 +1140,11 @@ delta_dirs(report_baton_t *b, svn_revnum
            svn_boolean_t start_empty, svn_depth_t wc_depth,
            svn_depth_t requested_depth, apr_pool_t *pool)
 {
-  svn_fs_root_t *s_root;
   apr_hash_t *s_entries = NULL, *t_entries;
   apr_hash_index_t *hi;
   apr_pool_t *subpool;
-  const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
-  path_info_t *info;
+  apr_array_header_t *t_ordered_entries = NULL;
+  int i;
 
   /* Compare the property lists.  If we're starting empty, pass a NULL
      source path so that we add all the properties.
@@ -1160,6 +1159,8 @@ delta_dirs(report_baton_t *b, svn_revnum
       /* Get the list of entries in each of source and target. */
       if (s_path && !start_empty)
         {
+          svn_fs_root_t *s_root;
+
           SVN_ERR(get_source_root(b, &s_root, s_rev));
           SVN_ERR(svn_fs_dir_entries(&s_entries, s_root, s_path, pool));
         }
@@ -1170,6 +1171,8 @@ delta_dirs(report_baton_t *b, svn_revnum
 
       while (1)
         {
+          path_info_t *info;
+          const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
           const svn_fs_dirent_t *s_entry, *t_entry;
 
           svn_pool_clear(subpool);
@@ -1197,10 +1200,9 @@ delta_dirs(report_baton_t *b, svn_revnum
           t_fullpath = svn_fspath__join(t_path, name, subpool);
           t_entry = svn_hash_gets(t_entries, name);
           s_fullpath = s_path ? svn_fspath__join(s_path, name, subpool) : NULL;
-          s_entry = s_entries ?
-            svn_hash_gets(s_entries, name) : NULL;
+          s_entry = s_entries ? svn_hash_gets(s_entries, name) : NULL;
 
-          /* The only special cases here are
+          /* The only special cases where we don't process the entry are
 
              - When requested_depth is files but the reported path is
              a directory.  This is technically a client error, but we
@@ -1208,10 +1210,10 @@ delta_dirs(report_baton_t *b, svn_revnum
 
              - When the reported depth is svn_depth_exclude.
           */
-          if ((! info || info->depth != svn_depth_exclude)
-              && (requested_depth != svn_depth_files
-                  || ((! t_entry || t_entry->kind != svn_node_dir)
-                      && (! s_entry || s_entry->kind != svn_node_dir))))
+          if (! ((requested_depth == svn_depth_files
+                  && ((t_entry && t_entry->kind == svn_node_dir)
+                      || (s_entry && s_entry->kind == svn_node_dir)))
+                 || (info && info->depth == svn_depth_exclude)))
             SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath,
                                  t_entry, dir_baton, e_fullpath, info,
                                  info ? info->depth
@@ -1240,13 +1242,13 @@ delta_dirs(report_baton_t *b, svn_revnum
                hi;
                hi = apr_hash_next(hi))
             {
-              const svn_fs_dirent_t *s_entry;
+              const svn_fs_dirent_t *s_entry = svn__apr_hash_index_val(hi);
 
               svn_pool_clear(subpool);
-              s_entry = svn__apr_hash_index_val(hi);
 
               if (svn_hash_gets(t_entries, s_entry->name) == NULL)
                 {
+                  const char *e_fullpath;
                   svn_revnum_t deleted_rev;
 
                   if (s_entry->kind == svn_node_file
@@ -1275,12 +1277,16 @@ delta_dirs(report_baton_t *b, svn_revnum
         }
 
       /* Loop over the dirents in the target. */
-      for (hi = apr_hash_first(pool, t_entries); hi; hi = apr_hash_next(hi))
+      SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
+                                       t_entries, pool));
+      for (i = 0; i < t_ordered_entries->nelts; ++i)
         {
-          const svn_fs_dirent_t *s_entry, *t_entry;
+          const svn_fs_dirent_t *t_entry
+             = APR_ARRAY_IDX(t_ordered_entries, i, svn_fs_dirent_t *);
+          const svn_fs_dirent_t *s_entry;
+          const char *s_fullpath, *t_fullpath, *e_fullpath;
 
           svn_pool_clear(subpool);
-          t_entry = svn__apr_hash_index_val(hi);
 
           if (is_depth_upgrade(wc_depth, requested_depth, t_entry->kind))
             {
@@ -1301,11 +1307,9 @@ delta_dirs(report_baton_t *b, svn_revnum
                       || requested_depth == svn_depth_files))
                 continue;
 
-              /* Look for an entry with the same name
-                 in the source dirents. */
+              /* Look for an entry with the same name in the source dirents. */
               s_entry = s_entries ?
-                  svn_hash_gets(s_entries, t_entry->name)
-                  : NULL;
+                  svn_hash_gets(s_entries, t_entry->name) : NULL;
               s_fullpath = s_entry ?
                   svn_fspath__join(s_path, t_entry->name, subpool) : NULL;
             }
@@ -1321,8 +1325,6 @@ delta_dirs(report_baton_t *b, svn_revnum
                                subpool));
         }
 
-
-      /* Destroy iteration subpool. */
       svn_pool_destroy(subpool);
     }
   return SVN_NO_ERROR;

Modified: subversion/branches/cache-server/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/repos.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/repos.c Tue Oct 15 08:52:06 2013
@@ -23,6 +23,7 @@
 #include <apr_pools.h>
 #include <apr_file_io.h>
 
+#include "svn_private_config.h"
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_dirent_uri.h"
@@ -38,7 +39,6 @@
 
 #include "private/svn_repos_private.h"
 #include "private/svn_subr_private.h"
-#include "svn_private_config.h" /* for SVN_TEMPLATE_ROOT_DIR */
 
 #include "repos.h"
 
@@ -1534,6 +1534,54 @@ svn_repos_open2(svn_repos_t **repos_p,
   return get_repos(repos_p, path, FALSE, FALSE, TRUE, fs_config, pool);
 }
 
+/* Baton used with fs_upgrade_notify, specifying the svn_repos layer
+ * notification parameters.
+ */
+struct fs_upgrade_notify_baton_t
+{
+  svn_repos_notify_func_t notify_func;
+  void *notify_baton;
+};
+
+/* Implements svn_fs_upgrade_notify_t as forwarding to a
+ * svn_repos_notify_func_t passed in a fs_upgrade_notify_baton_t* BATON.
+ */
+static svn_error_t *
+fs_upgrade_notify(void *baton,
+                  apr_uint64_t number,
+                  svn_fs_upgrade_notify_action_t action,
+                  apr_pool_t *pool)
+{
+  struct fs_upgrade_notify_baton_t *fs_baton = baton;
+
+  svn_repos_notify_t *notify = svn_repos_notify_create(
+                                svn_repos_notify_mutex_acquired, pool);
+  switch(action)
+    {
+      case svn_fs_upgrade_pack_revprops:
+        notify->shard = number;
+        notify->action = svn_repos_notify_pack_revprops;
+        break;
+
+      case svn_fs_upgrade_cleanup_revprops:
+        notify->shard = number;
+        notify->action = svn_repos_notify_cleanup_revprops;
+        break;
+
+      case svn_fs_upgrade_format_bumped:
+        notify->revision = number;
+        notify->action = svn_repos_notify_format_bumped;
+        break;
+
+      default:
+        /* unknown notification */
+        SVN_ERR_MALFUNCTION();
+    }
+
+  fs_baton->notify_func(fs_baton->notify_baton, notify, pool);
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_repos_upgrade2(const char *path,
@@ -1547,6 +1595,10 @@ svn_repos_upgrade2(const char *path,
   int format;
   apr_pool_t *subpool = svn_pool_create(pool);
 
+  struct fs_upgrade_notify_baton_t fs_notify_baton;
+  fs_notify_baton.notify_func = notify_func;
+  fs_notify_baton.notify_baton = notify_baton;
+
   /* Fetch a repository object; for the Berkeley DB backend, it is
      initialized with an EXCLUSIVE lock on the database.  This will at
      least prevent others from trying to read or write to it while we
@@ -1575,7 +1627,9 @@ svn_repos_upgrade2(const char *path,
   SVN_ERR(svn_io_write_version_file(format_path, format, subpool));
 
   /* Try to upgrade the filesystem. */
-  SVN_ERR(svn_fs_upgrade(repos->db_path, subpool));
+  SVN_ERR(svn_fs_upgrade2(repos->db_path,
+                          notify_func ? fs_upgrade_notify : NULL,
+                          &fs_notify_baton, NULL, NULL, subpool));
 
   /* Now overwrite our format file with the latest version. */
   SVN_ERR(svn_io_write_version_file(format_path, SVN_REPOS__FORMAT_NUMBER,

Modified: subversion/branches/cache-server/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_repos/rev_hunt.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_repos/rev_hunt.c Tue Oct 15 08:52:06 2013
@@ -23,8 +23,9 @@
 
 
 #include <string.h>
-#include "svn_compat.h"
+
 #include "svn_private_config.h"
+#include "svn_compat.h"
 #include "svn_hash.h"
 #include "svn_pools.h"
 #include "svn_error.h"
@@ -171,12 +172,8 @@ svn_repos_get_committed_info(svn_revnum_
   SVN_ERR(svn_fs_revision_proplist(&revprops, fs, *committed_rev, pool));
 
   /* Extract date and author from these revprops. */
-  committed_date_s = apr_hash_get(revprops,
-                                  SVN_PROP_REVISION_DATE,
-                                  sizeof(SVN_PROP_REVISION_DATE)-1);
-  last_author_s = apr_hash_get(revprops,
-                               SVN_PROP_REVISION_AUTHOR,
-                               sizeof(SVN_PROP_REVISION_AUTHOR)-1);
+  committed_date_s = svn_hash_gets(revprops, SVN_PROP_REVISION_DATE);
+  last_author_s = svn_hash_gets(revprops, SVN_PROP_REVISION_AUTHOR);
 
   *committed_date = committed_date_s ? committed_date_s->data : NULL;
   *last_author = last_author_s ? last_author_s->data : NULL;

Modified: subversion/branches/cache-server/subversion/libsvn_subr/adler32.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/adler32.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/adler32.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/adler32.c Tue Oct 15 08:52:06 2013
@@ -57,7 +57,7 @@ svn__adler32(apr_uint32_t checksum, cons
    */
   if (len >= 80)
     {
-      /* Larger buffers can be effiently handled by Marc Adler's
+      /* Larger buffers can be efficiently handled by Marc Adler's
        * optimized code. Also, new zlib versions will come with
        * SIMD code for x86 and x64.
        */
@@ -76,16 +76,16 @@ svn__adler32(apr_uint32_t checksum, cons
        * (approx. one clock tick per byte + 2 ticks loop overhead)
        */
       for (; len >= 8; len -= 8, input += 8)
-      {
-        s1 += input[0]; s2 += s1;
-        s1 += input[1]; s2 += s1;
-        s1 += input[2]; s2 += s1;
-        s1 += input[3]; s2 += s1;
-        s1 += input[4]; s2 += s1;
-        s1 += input[5]; s2 += s1;
-        s1 += input[6]; s2 += s1;
-        s1 += input[7]; s2 += s1;
-      }
+        {
+          s1 += input[0]; s2 += s1;
+          s1 += input[1]; s2 += s1;
+          s1 += input[2]; s2 += s1;
+          s1 += input[3]; s2 += s1;
+          s1 += input[4]; s2 += s1;
+          s1 += input[5]; s2 += s1;
+          s1 += input[6]; s2 += s1;
+          s1 += input[7]; s2 += s1;
+        }
 
       /* Adler-32 calculation as a simple two ticks per iteration loop.
        */

Modified: subversion/branches/cache-server/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/auth.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/auth.c Tue Oct 15 08:52:06 2013
@@ -26,13 +26,13 @@
 #include <apr_tables.h>
 #include <apr_strings.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_types.h"
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_auth.h"
 #include "svn_config.h"
-#include "svn_private_config.h"
 #include "svn_dso.h"
 #include "svn_version.h"
 #include "private/svn_dep_compat.h"
@@ -251,7 +251,9 @@ svn_auth_first_credentials(void **creden
     }
 
   if (! creds)
-    *state = NULL;
+    {
+      *state = NULL;
+    }
   else
     {
       /* Build an abstract iteration state. */
@@ -305,10 +307,12 @@ svn_auth_next_credentials(void **credent
         }
       else if (provider->vtable->next_credentials)
         {
-          SVN_ERR(provider->vtable->next_credentials(
-                      &creds, state->provider_iter_baton,
-                      provider->provider_baton, auth_baton->parameters,
-                      state->realmstring, auth_baton->pool));
+          SVN_ERR(provider->vtable->next_credentials(&creds,
+                                                     state->provider_iter_baton,
+                                                     provider->provider_baton,
+                                                     auth_baton->parameters,
+                                                     state->realmstring,
+                                                     auth_baton->pool));
         }
 
       if (creds != NULL)
@@ -374,12 +378,11 @@ svn_auth_save_credentials(svn_auth_iters
       provider = APR_ARRAY_IDX(state->table->providers, i,
                                svn_auth_provider_object_t *);
       if (provider->vtable->save_credentials)
-        SVN_ERR(provider->vtable->save_credentials
-                (&save_succeeded, creds,
-                 provider->provider_baton,
-                 auth_baton->parameters,
-                 state->realmstring,
-                 pool));
+        SVN_ERR(provider->vtable->save_credentials(&save_succeeded, creds,
+                                                   provider->provider_baton,
+                                                   auth_baton->parameters,
+                                                   state->realmstring,
+                                                   pool));
 
       if (save_succeeded)
         break;
@@ -478,7 +481,8 @@ svn_auth_get_platform_specific_provider(
               check_list[0].version_query = version_function;
               check_list[1].label = NULL;
               check_list[1].version_query = NULL;
-              SVN_ERR(svn_ver_check_list(svn_subr_version(), check_list));
+              SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
+                                          svn_ver_equal));
             }
           if (apr_dso_sym(&provider_function_symbol,
                           dso,

Modified: subversion/branches/cache-server/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/cache-inprocess.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/cache-inprocess.c Tue Oct 15 08:52:06 2013
@@ -190,7 +190,6 @@ inprocess_cache_get_internal(char **buff
 {
   struct cache_entry *entry = apr_hash_get(cache->hash, key, cache->klen);
 
-  *buffer = NULL;
   if (entry)
     {
       SVN_ERR(move_page_to_front(cache, entry->page));
@@ -201,6 +200,11 @@ inprocess_cache_get_internal(char **buff
 
       *size = entry->size;
     }
+  else
+    {
+      *buffer = NULL;
+      *size = 0;
+    }
 
   return SVN_NO_ERROR;
 }
@@ -213,25 +217,64 @@ inprocess_cache_get(void **value_p,
                     apr_pool_t *result_pool)
 {
   inprocess_cache_t *cache = cache_void;
-  char* buffer = NULL;
-  apr_size_t size = 0;
+
+  if (key)
+    {
+      char* buffer;
+      apr_size_t size;
+
+      SVN_MUTEX__WITH_LOCK(cache->mutex,
+                           inprocess_cache_get_internal(&buffer,
+                                                        &size,
+                                                        cache,
+                                                        key,
+                                                        result_pool));
+      /* deserialize the buffer content. Usually, this will directly
+         modify the buffer content directly. */
+      *found = (buffer != NULL);
+      if (!buffer || !size)
+        *value_p = NULL;
+      else
+        return cache->deserialize_func(value_p, buffer, size, result_pool);
+    }
+  else
+    {
+      *value_p = NULL;
+      *found = FALSE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+inprocess_cache_has_key_internal(svn_boolean_t *found,
+                                 inprocess_cache_t *cache,
+                                 const void *key,
+                                 apr_pool_t *scratch_pool)
+{
+  *found = apr_hash_get(cache->hash, key, cache->klen) != NULL;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+inprocess_cache_has_key(svn_boolean_t *found,
+                        void *cache_void,
+                        const void *key,
+                        apr_pool_t *scratch_pool)
+{
+  inprocess_cache_t *cache = cache_void;
 
   if (key)
     SVN_MUTEX__WITH_LOCK(cache->mutex,
-                         inprocess_cache_get_internal(&buffer,
-                                                      &size,
-                                                      cache,
-                                                      key,
-                                                      result_pool));
+                         inprocess_cache_has_key_internal(found,
+                                                          cache,
+                                                          key,
+                                                          scratch_pool));
+  else
+    *found = FALSE;
 
-  /* deserialize the buffer content. Usually, this will directly
-     modify the buffer content directly.
-   */
-  *value_p = NULL;
-  *found = buffer != NULL;
-  return buffer && size
-    ? cache->deserialize_func(value_p, buffer, size, result_pool)
-    : SVN_NO_ERROR;
+  return SVN_NO_ERROR;
 }
 
 /* Removes PAGE from the LRU list, removes all of its entries from
@@ -592,6 +635,7 @@ inprocess_cache_get_info(void *cache_voi
 
 static svn_cache__vtable_t inprocess_cache_vtable = {
   inprocess_cache_get,
+  inprocess_cache_has_key,
   inprocess_cache_set,
   inprocess_cache_iter,
   inprocess_cache_is_cachable,