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/16 01:44:46 UTC

svn commit: r1532597 [5/10] - in /subversion/branches/log-addressing: ./ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ notes/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/a...

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/tree.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/tree.c Tue Oct 15 23:44:41 2013
@@ -60,6 +60,7 @@
 #include "pack.h"
 #include "temp_serializer.h"
 #include "transaction.h"
+#include "util.h"
 
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_subr_private.h"
@@ -132,6 +133,12 @@ static svn_error_t *make_txn_root(svn_fs
                                   apr_uint32_t flags,
                                   apr_pool_t *pool);
 
+static svn_error_t *fs_closest_copy(svn_fs_root_t **root_p,
+                                    const char **path_p,
+                                    svn_fs_root_t *root,
+                                    const char *path,
+                                    apr_pool_t *pool);
+
 
 /*** Node Caching ***/
 
@@ -2244,7 +2251,7 @@ fs_dir_optimal_order(apr_array_header_t 
 {
   *ordered_p
     = svn_fs_fs__order_dir_entries(root->fs, entries,
-                                   svn_fs_revision_root_revision(root),
+                                   root->rev,
                                    pool);
 
   return SVN_NO_ERROR;
@@ -2388,15 +2395,89 @@ fs_same_p(svn_boolean_t *same_p,
   return SVN_NO_ERROR;
 }
 
+/* Type to select the various behavioral modes of copy_helper.
+ */
+typedef enum copy_type_t
+{
+  /* add without history */
+  copy_type_plain_add,
+
+  /* add with history */
+  copy_type_add_with_history,
+
+  /* move (always with history) */
+  copy_type_move
+} copy_type_t;
+
+/* Set CHANGES to TRUE if PATH in ROOT is unchanged in REVISION if the
+   same files system.  If the content is identical, parent path copies and
+   deletions still count as changes.  Use POOL for temporary allocations.
+   Not that we will return an error if PATH does not exist in ROOT or
+   REVISION- */
+static svn_error_t *
+is_changed_node(svn_boolean_t *changed,
+                svn_fs_root_t *root,
+                const char *path,
+                svn_revnum_t revision,
+                apr_pool_t *pool)
+{
+  dag_node_t *node, *rev_node;
+  svn_fs_root_t *rev_root;
+  svn_fs_root_t *copy_from_root1, *copy_from_root2;
+  const char *copy_from_path1, *copy_from_path2;
+
+  SVN_ERR(svn_fs_fs__revision_root(&rev_root, root->fs, revision, pool));
+
+  /* Get the NODE for FROM_PATH in FROM_ROOT.*/
+  SVN_ERR(get_dag(&node, root, path, TRUE, pool));
+  SVN_ERR(get_dag(&rev_node, rev_root, path, TRUE, pool));
+
+  /* different ID -> got changed */
+  if (!svn_fs_fs__id_eq(svn_fs_fs__dag_get_id(node),
+                        svn_fs_fs__dag_get_id(rev_node)))
+    {
+      *changed = TRUE;
+       return SVN_NO_ERROR;
+    }
+
+  /* same node. might still be a lazy copy with separate history */
+  SVN_ERR(fs_closest_copy(&copy_from_root1, &copy_from_path1, root,
+                          path, pool));
+  SVN_ERR(fs_closest_copy(&copy_from_root2, &copy_from_path2, rev_root,
+                          path, pool));
+
+  if (copy_from_root1 == NULL && copy_from_root2 == NULL)
+    {
+      /* never copied -> same line of history */
+      *changed = FALSE;
+    }
+  else if (copy_from_root1 != NULL && copy_from_root2 != NULL)
+    {
+      /* both got copied. At the same time & location? */
+      *changed = (copy_from_root1->rev != copy_from_root2->rev)
+                 || strcmp(copy_from_path1, copy_from_path2);
+    }
+  else
+    {
+      /* one is a copy while the other one is not
+       * -> different lines of history */
+      *changed = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Copy the node at FROM_PATH under FROM_ROOT to TO_PATH under
-   TO_ROOT.  If PRESERVE_HISTORY is set, then the copy is recorded in
-   the copies table.  Perform temporary allocations in POOL. */
+   TO_ROOT.  COPY_TYPE determines whether then the copy is recorded in
+   the copies table and whether it is being marked as a move.
+   Perform temporary allocations in POOL. */
 static svn_error_t *
 copy_helper(svn_fs_root_t *from_root,
             const char *from_path,
             svn_fs_root_t *to_root,
             const char *to_path,
-            svn_boolean_t preserve_history,
+            copy_type_t copy_type,
             apr_pool_t *pool)
 {
   dag_node_t *from_node;
@@ -2413,11 +2494,52 @@ copy_helper(svn_fs_root_t *from_root,
        _("Cannot copy between two different filesystems ('%s' and '%s')"),
        from_root->fs->path, to_root->fs->path);
 
+  /* more things that we can't do ATM */
   if (from_root->is_txn_root)
     return svn_error_create
       (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
        _("Copy from mutable tree not currently supported"));
 
+  if (! to_root->is_txn_root)
+    return svn_error_create
+      (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+       _("Copy immutable tree not supported"));
+
+  /* move support comes with a number of conditions ... */
+  if (copy_type == copy_type_move)
+    {
+      /* if we don't copy from the TXN's base rev, check that the path has
+         not been touched in that revision range */
+      if (from_root->rev != txn_id->revision)
+        {
+          svn_boolean_t changed = TRUE;
+          svn_error_t *err = is_changed_node(&changed, from_root,
+                                             from_path, txn_id->revision,
+                                             pool);
+
+          /* Only "not found" is considered to be caused by out-of-date-ness.
+             Everything else means something got very wrong ... */
+          if (err && err->apr_err != SVN_ERR_FS_NOT_FOUND)
+            return svn_error_trace(err);
+
+          /* here error means "out of data" */
+          if (err || changed)
+            {
+              svn_error_clear(err);
+              return svn_error_create(SVN_ERR_FS_OUT_OF_DATE, NULL,
+                                      _("Move-from node is out-of-date"));
+            }
+
+          /* always move from the txn's base rev */
+          SVN_ERR(svn_fs_fs__revision_root(&from_root, from_root->fs,
+                                           txn_id->revision, pool));
+        }
+
+      /* does the FS support moves at all? */
+      if (!svn_fs_fs__supports_move(to_root->fs))
+        copy_type = copy_type_add_with_history;
+    }
+
   /* Get the NODE for FROM_PATH in FROM_ROOT.*/
   SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));
 
@@ -2454,14 +2576,20 @@ copy_helper(svn_fs_root_t *from_root,
          operation is a replacement, not an addition. */
       if (to_parent_path->node)
         {
-          kind = svn_fs_path_change_replace;
+          kind = copy_type == copy_type_move
+               ? svn_fs_path_change_movereplace
+               : svn_fs_path_change_replace;
+
           if (svn_fs_fs__fs_supports_mergeinfo(to_root->fs))
             SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_start,
                                                        to_parent_path->node));
         }
       else
         {
-          kind = svn_fs_path_change_add;
+          kind = copy_type == copy_type_move
+               ? svn_fs_path_change_move
+               : svn_fs_path_change_add;
+
           mergeinfo_start = 0;
         }
 
@@ -2479,12 +2607,12 @@ copy_helper(svn_fs_root_t *from_root,
       SVN_ERR(svn_fs_fs__dag_copy(to_parent_path->parent->node,
                                   to_parent_path->entry,
                                   from_node,
-                                  preserve_history,
+                                  copy_type != copy_type_plain_add,
                                   from_root->rev,
                                   from_canonpath,
                                   txn_id, pool));
 
-      if (kind == svn_fs_path_change_replace)
+      if (kind != svn_fs_path_change_add)
         SVN_ERR(dag_node_cache_invalidate(to_root,
                                           parent_path_path(to_parent_path,
                                                            pool), pool));
@@ -2541,7 +2669,7 @@ fs_copy(svn_fs_root_t *from_root,
                                      to_root,
                                      svn_fs__canonicalize_abspath(to_path,
                                                                   pool),
-                                     TRUE, pool));
+                                     copy_type_add_with_history, pool));
 }
 
 
@@ -2559,7 +2687,29 @@ fs_revision_link(svn_fs_root_t *from_roo
 
   path = svn_fs__canonicalize_abspath(path, pool);
   return svn_error_trace(copy_helper(from_root, path, to_root, path,
-                                     FALSE, pool));
+                                     copy_type_plain_add, pool));
+}
+
+
+/* Create a copy of FROM_PATH in FROM_ROOT named TO_PATH in TO_ROOT and mark
+   it as a Move.  If FROM_PATH is a directory, copy it recursively. 
+   Temporary allocations are from POOL.*/
+static svn_error_t *
+fs_move(svn_fs_root_t *from_root,
+        const char *from_path,
+        svn_fs_root_t *to_root,
+        const char *to_path,
+        apr_pool_t *pool)
+{
+  SVN_ERR(check_newline(to_path, pool));
+
+  return svn_error_trace(copy_helper(from_root,
+                                     svn_fs__canonicalize_abspath(from_path,
+                                                                  pool),
+                                     to_root,
+                                     svn_fs__canonicalize_abspath(to_path,
+                                                                  pool),
+                                     copy_type_move, pool));
 }
 
 
@@ -4134,6 +4284,9 @@ static root_vtable_t root_vtable = {
   fs_node_origin_rev,
   fs_node_created_path,
   fs_delete_node,
+  fs_copy,
+  fs_revision_link,
+  fs_move,
   fs_copied_from,
   fs_closest_copy,
   fs_node_prop,
@@ -4143,8 +4296,6 @@ static root_vtable_t root_vtable = {
   fs_dir_entries,
   fs_dir_optimal_order,
   fs_make_dir,
-  fs_copy,
-  fs_revision_link,
   fs_file_length,
   fs_file_checksum,
   fs_file_contents,
@@ -4326,19 +4477,28 @@ verify_node(dag_node_t *node,
         {
           svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
           dag_node_t *child;
-          svn_revnum_t child_rev;
           apr_int64_t child_mergeinfo;
 
           svn_pool_clear(iterpool);
 
           /* Compute CHILD_REV. */
-          SVN_ERR(svn_fs_fs__dag_get_node(&child, fs, dirent->id, iterpool));
-          SVN_ERR(svn_fs_fs__dag_get_revision(&child_rev, child, iterpool));
-
-          if (child_rev == rev)
-            SVN_ERR(verify_node(child, rev, iterpool));
+          if (svn_fs_fs__id_rev(dirent->id) == rev)
+            {
+              SVN_ERR(svn_fs_fs__dag_get_node(&child, fs, dirent->id,
+                                              iterpool));
+              SVN_ERR(verify_node(child, rev, iterpool));
+              SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&child_mergeinfo,
+                                                         child));
+            }
+          else
+            {
+              /* access mergeinfo counter with minimal overhead */
+              node_revision_t *noderev;
+              SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, dirent->id,
+                                                   iterpool));
+              child_mergeinfo = noderev->mergeinfo_count;
+            }
 
-          SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&child_mergeinfo, child));
           children_mergeinfo += child_mergeinfo;
         }
 

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.c Tue Oct 15 23:44:41 2013
@@ -637,3 +637,11 @@ svn_fs_fs__use_log_addressing(svn_fs_t *
   return ffd->min_log_addressing_rev != SVN_INVALID_REVNUM
       && ffd->min_log_addressing_rev <= rev;
 }
+
+svn_boolean_t
+svn_fs_fs__supports_move(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  return ffd->format >= SVN_FS_FS__MIN_MOVE_SUPPORT_FORMAT;
+}

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.h Tue Oct 15 23:44:41 2013
@@ -385,4 +385,8 @@ svn_boolean_t
 svn_fs_fs__use_log_addressing(svn_fs_t *fs,
                               svn_revnum_t rev);
 
-#endif
+/* Return TRUE if FS's format supports moves to be recorded natively. */
+svn_boolean_t
+svn_fs_fs__supports_move(svn_fs_t *fs);
+
+#endif
\ No newline at end of file

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/util.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/verify.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/verify.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/libsvn_fs_x:r1516632-1532579
  Merged /subversion/branches/fsfs-improvements/subversion/libsvn_fs_x:r1499981-1509278,1516645-1532583

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.c Tue Oct 15 23:44:41 2013
@@ -413,6 +413,57 @@ svn_fs_x__get_node_revision(node_revisio
 
 
 svn_error_t *
+svn_fs_x__get_mergeinfo_count(apr_int64_t *count,
+                              svn_fs_t *fs,
+                              const svn_fs_id_t *id,
+                              apr_pool_t *pool)
+{
+  node_revision_t *noderev;
+
+  /* If we want a full acccess log, we need to provide full data and
+     cannot take shortcuts here. */
+#if !defined(SVN_FS_X__LOG_ACCESS)
+
+  /* First, try a noderevs container cache lookup. */
+  if (! svn_fs_x__id_is_txn(id))
+    {
+      /* noderevs in rev / pack files can be cached */
+      const svn_fs_x__id_part_t *rev_item = svn_fs_x__id_rev_item(id);
+      fs_x_data_t *ffd = fs->fsap_data;
+
+      if (   svn_fs_x__is_packed_rev(fs, rev_item->revision)
+          && ffd->noderevs_container_cache)
+        {
+          pair_cache_key_t key;
+          apr_off_t offset;
+          apr_uint32_t sub_item;
+          svn_boolean_t is_cached;
+
+          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs,
+                                        rev_item->revision, NULL,
+                                        rev_item->number, pool));
+          key.revision = svn_fs_x__packed_base_rev(fs, rev_item->revision);
+          key.second = offset;
+
+          SVN_ERR(svn_cache__get_partial((void **)count, &is_cached,
+                                         ffd->noderevs_container_cache, &key,
+                                         svn_fs_x__mergeinfo_count_get_func,
+                                         &sub_item, pool));
+          if (is_cached)
+            return SVN_NO_ERROR;
+        }
+    }
+#endif
+
+  /* fallback to the naive implementation handling all edge cases */
+  SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool));
+  *count = noderev->mergeinfo_count;
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_fs_x__rev_get_root(svn_fs_id_t **root_id_p,
                        svn_fs_t *fs,
                        svn_revnum_t rev,

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.h Tue Oct 15 23:44:41 2013
@@ -39,6 +39,14 @@ svn_fs_x__get_node_revision(node_revisio
                             const svn_fs_id_t *id,
                             apr_pool_t *pool);
 
+/* Set *COUNT to the value of the mergeinfo_count member of the node-
+   revision for the node ID in FS.  Do any allocations in POOL. */
+svn_error_t *
+svn_fs_x__get_mergeinfo_count(apr_int64_t *count,
+                              svn_fs_t *fs,
+                              const svn_fs_id_t *id,
+                              apr_pool_t *pool);
+
 /* Set *ROOT_ID to the node-id for the root of revision REV in
    filesystem FS.  Do any allocations in POOL. */
 svn_error_t *

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/cached_data.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.c Tue Oct 15 23:44:41 2013
@@ -60,6 +60,8 @@
 #define CHANGE_KIND_DELETE  0x00040
 #define CHANGE_KIND_REPLACE 0x00060
 #define CHANGE_KIND_RESET   0x00080
+#define CHANGE_KIND_MOVE    0x000A0
+#define CHANGE_KIND_MOVEREPLACE 0x000C0
 
 /* Our internal representation of a change */
 typedef struct binary_change_t

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/changes.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/fs.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/fs.c Tue Oct 15 23:44:41 2013
@@ -229,10 +229,13 @@ initialize_fs_struct(svn_fs_t *fs)
 /* This implements the fs_library_vtable_t.create() API.  Create a new
    fsx-backed Subversion filesystem at path PATH and link it into
    *FS.  Perform temporary allocations in POOL, and fs-global allocations
-   in COMMON_POOL. */
+   in COMMON_POOL.  The latter must be serialized using COMMON_POOL_LOCK. */
 static svn_error_t *
-x_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
-          apr_pool_t *common_pool)
+x_create(svn_fs_t *fs,
+         const char *path,
+         svn_mutex__t *common_pool_lock,
+         apr_pool_t *pool,
+         apr_pool_t *common_pool)
 {
   SVN_ERR(svn_fs__check_fs(fs, FALSE));
 
@@ -241,7 +244,10 @@ x_create(svn_fs_t *fs, const char *path,
   SVN_ERR(svn_fs_x__create(fs, path, pool));
 
   SVN_ERR(svn_fs_x__initialize_caches(fs, pool));
-  return x_serialized_init(fs, common_pool, pool);
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       x_serialized_init(fs, common_pool, pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -251,17 +257,26 @@ x_create(svn_fs_t *fs, const char *path,
 /* This implements the fs_library_vtable_t.open() API.  Open an FSX
    Subversion filesystem located at PATH, set *FS to point to the
    correct vtable for the filesystem.  Use POOL for any temporary
-   allocations, and COMMON_POOL for fs-global allocations. */
+   allocations, and COMMON_POOL for fs-global allocations.
+   The latter must be serialized using COMMON_POOL_LOCK.  */
 static svn_error_t *
-x_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
-        apr_pool_t *common_pool)
+x_open(svn_fs_t *fs,
+       const char *path,
+       svn_mutex__t *common_pool_lock,
+       apr_pool_t *pool,
+       apr_pool_t *common_pool)
 {
+  SVN_ERR(svn_fs__check_fs(fs, FALSE));
+
   SVN_ERR(initialize_fs_struct(fs));
 
   SVN_ERR(svn_fs_x__open(fs, path, pool));
 
   SVN_ERR(svn_fs_x__initialize_caches(fs, pool));
-  return x_serialized_init(fs, common_pool, pool);
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       x_serialized_init(fs, common_pool, pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -270,7 +285,9 @@ x_open(svn_fs_t *fs, const char *path, a
 static svn_error_t *
 x_open_for_recovery(svn_fs_t *fs,
                     const char *path,
-                    apr_pool_t *pool, apr_pool_t *common_pool)
+                    svn_mutex__t *common_pool_lock,
+                    apr_pool_t *pool,
+                    apr_pool_t *common_pool)
 {
   /* Recovery for FSX is currently limited to recreating the 'current'
      file from the latest revision. */
@@ -288,7 +305,7 @@ x_open_for_recovery(svn_fs_t *fs,
                                      "0 1 1\n", pool));
 
   /* Now open the filesystem properly by calling the vtable method directly. */
-  return x_open(fs, path, pool, common_pool);
+  return x_open(fs, path, common_pool_lock, pool, common_pool);
 }
 
 
@@ -301,14 +318,11 @@ x_upgrade(svn_fs_t *fs,
           void *notify_baton,
           svn_cancel_func_t cancel_func,
           void *cancel_baton,
+          svn_mutex__t *common_pool_lock,
           apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_x__open(fs, path, pool));
-  SVN_ERR(svn_fs_x__initialize_caches(fs, pool));
-  SVN_ERR(x_serialized_init(fs, common_pool, pool));
+  SVN_ERR(x_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_x__upgrade(fs, notify_func, notify_baton,
                            cancel_func, cancel_baton, pool);
 }
@@ -321,14 +335,11 @@ x_verify(svn_fs_t *fs, const char *path,
          void *notify_baton,
          svn_cancel_func_t cancel_func,
          void *cancel_baton,
+         svn_mutex__t *common_pool_lock,
          apr_pool_t *pool,
          apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_x__open(fs, path, pool));
-  SVN_ERR(svn_fs_x__initialize_caches(fs, pool));
-  SVN_ERR(x_serialized_init(fs, common_pool, pool));
+  SVN_ERR(x_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_x__verify(fs, start, end, notify_func, notify_baton,
                           cancel_func, cancel_baton, pool);
 }
@@ -340,14 +351,11 @@ x_pack(svn_fs_t *fs,
        void *notify_baton,
        svn_cancel_func_t cancel_func,
        void *cancel_baton,
+       svn_mutex__t *common_pool_lock,
        apr_pool_t *pool,
        apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_x__open(fs, path, pool));
-  SVN_ERR(svn_fs_x__initialize_caches(fs, pool));
-  SVN_ERR(x_serialized_init(fs, common_pool, pool));
+  SVN_ERR(x_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_x__pack(fs, notify_func, notify_baton,
                         cancel_func, cancel_baton, pool);
 }

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/hotcopy.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/hotcopy.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/index.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/index.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/low_level.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/low_level.c Tue Oct 15 23:44:41 2013
@@ -53,6 +53,8 @@
 #define ACTION_DELETE      "delete"
 #define ACTION_REPLACE     "replace"
 #define ACTION_RESET       "reset"
+#define ACTION_MOVE        "move"
+#define ACTION_MOVEREPLACE "movereplace"
 
 /* True and False flags. */
 #define FLAG_TRUE          "true"
@@ -828,6 +830,14 @@ read_change(change_t **change_p,
     {
       info->change_kind = svn_fs_path_change_reset;
     }
+  else if (strcmp(str, ACTION_MOVE) == 0)
+    {
+      info->change_kind = svn_fs_path_change_move;
+    }
+  else if (strcmp(str, ACTION_MOVEREPLACE) == 0)
+    {
+      info->change_kind = svn_fs_path_change_movereplace;
+    }
   else
     {
       return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -961,6 +971,12 @@ write_change_entry(svn_stream_t *stream,
     case svn_fs_path_change_reset:
       change_string = ACTION_RESET;
       break;
+    case svn_fs_path_change_move:
+      change_string = ACTION_MOVE;
+      break;
+    case svn_fs_path_change_movereplace:
+      change_string = ACTION_MOVEREPLACE;
+      break;
     default:
       return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                _("Invalid change type %d"),

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/low_level.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.c Tue Oct 15 23:44:41 2013
@@ -1014,3 +1014,25 @@ svn_fs_x__noderevs_get_func(void **out,
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_fs_x__mergeinfo_count_get_func(void **out,
+                                   const void *data,
+                                   apr_size_t data_len,
+                                   void *baton,
+                                   apr_pool_t *pool)
+{
+  binary_noderev_t *binary_noderev;
+  apr_array_header_t noderevs;
+
+  apr_uint32_t idx = *(apr_uint32_t *)baton;
+  const svn_fs_x__noderevs_t *container = data;
+
+  /* Resolve all container pointers */
+  resolve_apr_array_header(&noderevs, container, &container->noderevs);
+  binary_noderev = &APR_ARRAY_IDX(&noderevs, idx, binary_noderev_t);
+  
+  *(apr_int64_t *)out = binary_noderev->mergeinfo_count;
+
+  return SVN_NO_ERROR;
+}

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.h Tue Oct 15 23:44:41 2013
@@ -127,4 +127,15 @@ svn_fs_x__noderevs_get_func(void **out,
                              void *baton,
                              apr_pool_t *pool);
 
+/* Implements svn_cache__partial_getter_func_t for the mergeinfo_count in
+ * the stored noderevs, setting *OUT to the apr_int64_t counter value of
+ * the noderev selected by the apr_uint32_t index passed in as *BATON.
+ */
+svn_error_t *
+svn_fs_x__mergeinfo_count_get_func(void **out,
+                                   const void *data,
+                                   apr_size_t data_len,
+                                   void *baton,
+                                   apr_pool_t *pool);
+
 #endif

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/noderevs.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/pack.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/pack.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/recovery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/recovery.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/reps.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/reps.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/revprops.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/string_table.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/string_table.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.c Tue Oct 15 23:44:41 2013
@@ -646,6 +646,33 @@ unparse_dir_entries(apr_hash_t **str_ent
   return SVN_NO_ERROR;
 }
 
+/* Copy the contents of NEW_CHANGE into OLD_CHANGE assuming that both
+   belong to the same path.  Allocate copies in POOL.
+ */
+static void
+replace_change(svn_fs_path_change2_t *old_change,
+               const svn_fs_path_change2_t *new_change,
+               apr_pool_t *pool)
+{
+  /* An add at this point must be following a previous delete,
+      so treat it just like a replace. */
+  old_change->node_kind = new_change->node_kind;
+  old_change->node_rev_id = svn_fs_x__id_copy(new_change->node_rev_id, pool);
+  old_change->text_mod = new_change->text_mod;
+  old_change->prop_mod = new_change->prop_mod;
+  if (new_change->copyfrom_rev == SVN_INVALID_REVNUM)
+    {
+      old_change->copyfrom_rev = SVN_INVALID_REVNUM;
+      old_change->copyfrom_path = NULL;
+    }
+  else
+    {
+      old_change->copyfrom_rev = new_change->copyfrom_rev;
+      old_change->copyfrom_path = apr_pstrdup(pool,
+                                              new_change->copyfrom_path);
+    }
+}
+
 /* Merge the internal-use-only CHANGE into a hash of public-FS
    svn_fs_path_change2_t CHANGES, collapsing multiple changes into a
    single summarical (is that real word?) change per path.  Also keep
@@ -683,11 +710,13 @@ fold_change(apr_hash_t *changes,
            _("Invalid change ordering: new node revision ID "
              "without delete"));
 
-      /* Sanity check: an add, replacement, or reset must be the first
+      /* Sanity check: an add, replacement, move, or reset must be the first
          thing to follow a deletion. */
       if ((old_change->change_kind == svn_fs_path_change_delete)
           && (! ((info->change_kind == svn_fs_path_change_replace)
                  || (info->change_kind == svn_fs_path_change_reset)
+                 || (info->change_kind == svn_fs_path_change_movereplace)
+                 || (info->change_kind == svn_fs_path_change_move)
                  || (info->change_kind == svn_fs_path_change_add))))
         return svn_error_create
           (SVN_ERR_FS_CORRUPT, NULL,
@@ -712,7 +741,8 @@ fold_change(apr_hash_t *changes,
           break;
 
         case svn_fs_path_change_delete:
-          if (old_change->change_kind == svn_fs_path_change_add)
+          if ((old_change->change_kind == svn_fs_path_change_add)
+              || (old_change->change_kind == svn_fs_path_change_move))
             {
               /* If the path was introduced in this transaction via an
                  add, and we are deleting it, just remove the path
@@ -734,22 +764,16 @@ fold_change(apr_hash_t *changes,
         case svn_fs_path_change_replace:
           /* An add at this point must be following a previous delete,
              so treat it just like a replace. */
+          replace_change(old_change, info, pool);
           old_change->change_kind = svn_fs_path_change_replace;
-          old_change->node_rev_id = svn_fs_x__id_copy(info->node_rev_id,
-                                                      pool);
-          old_change->text_mod = info->text_mod;
-          old_change->prop_mod = info->prop_mod;
-          if (info->copyfrom_rev == SVN_INVALID_REVNUM)
-            {
-              old_change->copyfrom_rev = SVN_INVALID_REVNUM;
-              old_change->copyfrom_path = NULL;
-            }
-          else
-            {
-              old_change->copyfrom_rev = info->copyfrom_rev;
-              old_change->copyfrom_path = apr_pstrdup(pool,
-                                                      info->copyfrom_path);
-            }
+          break;
+
+        case svn_fs_path_change_move:
+        case svn_fs_path_change_movereplace:
+          /* A move at this point must be following a previous delete,
+             so treat it just like a replacing move. */
+          replace_change(old_change, info, pool);
+          old_change->change_kind = svn_fs_path_change_movereplace;
           break;
 
         case svn_fs_path_change_modify:
@@ -816,7 +840,8 @@ process_changes(apr_hash_t *changed_path
       */
 
       if ((change->info.change_kind == svn_fs_path_change_delete)
-           || (change->info.change_kind == svn_fs_path_change_replace))
+           || (change->info.change_kind == svn_fs_path_change_replace)
+           || (change->info.change_kind == svn_fs_path_change_movereplace))
         {
           apr_hash_index_t *hi;
 
@@ -2655,25 +2680,37 @@ write_final_rev(const svn_fs_id_t **new_
   return SVN_NO_ERROR;
 }
 
-/* Write the changed path info from transaction TXN_ID in filesystem
-   FS to the permanent rev-file FILE.  *OFFSET_P is set the to offset
-   in the file of the beginning of this information.  Perform
-   temporary allocations in POOL. */
+/* Write the changed path info CHANGED_PATHS of transaction TXN_ID to the
+   permanent rev-file FILE representing NEW_REV in filesystem FS.  *OFFSET_P
+   is set the to offset in the file of the beginning of this information.
+   Perform temporary allocations in POOL. */
 static svn_error_t *
 write_final_changed_path_info(apr_off_t *offset_p,
                               apr_file_t *file,
                               svn_fs_t *fs,
                               const svn_fs_x__id_part_t *txn_id,
+                              apr_hash_t *changed_paths,
+                              svn_revnum_t new_rev,
                               apr_pool_t *pool)
 {
-  apr_hash_t *changed_paths;
   apr_off_t offset;
+  apr_hash_index_t *hi;
   svn_fs_x__p2l_entry_t entry;
   svn_fs_x__id_part_t rev_item
     = {SVN_INVALID_REVNUM, SVN_FS_X__ITEM_INDEX_CHANGES};
 
   SVN_ERR(svn_fs_x__get_file_offset(&offset, file, pool));
-  SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, fs, txn_id, pool));
+
+  /* all moves specify the "copy-from-rev" as REV-1 */
+  for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+    {
+      svn_fs_path_change2_t *change;
+      apr_hash_this(hi, NULL, NULL, (void **)&change);
+
+      if (change->change_kind == svn_fs_path_change_move)
+        change->copyfrom_rev = new_rev - 1;
+    }
+
   SVN_ERR(svn_fs_x__write_changes(svn_stream_from_aprfile2(file, TRUE, pool),
                                   fs, changed_paths, TRUE, pool));
 
@@ -2814,6 +2851,163 @@ verify_locks(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* If CHANGE is move, verify that there is no other move with the same
+   copy-from path in SOURCE_PATHS already (parent or sub-node moves are fine).
+   Add the source path to SOURCE_PATHS after successful verification. */
+static svn_error_t *
+check_for_duplicate_move_source(apr_hash_t *source_paths,
+                                change_t *change)
+{
+  if (   change->info.change_kind == svn_fs_path_change_move
+      || change->info.change_kind == svn_fs_path_change_movereplace)
+    if (change->info.copyfrom_path)
+      {
+        if (apr_hash_get(source_paths, change->info.copyfrom_path,
+                         APR_HASH_KEY_STRING))
+          return svn_error_createf(SVN_ERR_FS_AMBIGUOUS_MOVE, NULL,
+                      _("Path '%s' has been moved to more than one target"),
+                                   change->info.copyfrom_path);
+
+        apr_hash_set(source_paths, change->info.copyfrom_path,
+                     APR_HASH_KEY_STRING, change->info.copyfrom_path);
+      }
+
+  return SVN_NO_ERROR;
+}
+
+/* Verify that the moves we are about to commit with TXN_ID in FS are unique
+   and the respective copy sources have been deleted.  OLD_REV is the last
+   committed revision.  CHANGED_PATHS is the list of changes paths in this
+   txn.  Use POOL for temporary allocations. */
+static svn_error_t *
+verify_moves(svn_fs_t *fs,
+             const svn_fs_x__id_part_t *txn_id,
+             svn_revnum_t old_rev,
+             apr_hash_t *changed_paths,
+             apr_pool_t *pool)
+{
+  apr_hash_t *source_paths = apr_hash_make(pool);
+  svn_revnum_t revision;
+  apr_pool_t *iter_pool = svn_pool_create(pool);
+  apr_hash_index_t *hi;
+  int i;
+  apr_array_header_t *moves
+    = apr_array_make(pool, 16, sizeof(svn_sort__item_t));
+  apr_array_header_t *deletions
+    = apr_array_make(pool, 16, sizeof(const char *));
+
+  /* extract moves and deletions from the current txn's change list */
+
+  for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+    {
+      const char *path;
+      apr_ssize_t len;
+      change_t *change;
+      apr_hash_this(hi, (const void**)&path, &len, (void**)&change);
+
+      if (   change->info.copyfrom_path
+          && (   change->info.change_kind == svn_fs_path_change_move
+              || change->info.change_kind == svn_fs_path_change_movereplace))
+        {
+          svn_sort__item_t *item = apr_array_push(moves);
+          item->key = path;
+          item->klen = len;
+          item->value = change;
+        }
+
+      if (   change->info.change_kind == svn_fs_path_change_delete
+          || change->info.change_kind == svn_fs_path_change_replace
+          || change->info.change_kind == svn_fs_path_change_movereplace)
+        APR_ARRAY_PUSH(deletions, const char *) = path;
+    }
+
+  /* no moves? -> done here */
+
+  if (moves->nelts == 0)
+    return SVN_NO_ERROR;
+
+  /* correct the deletions that refer to moved paths and make them refer to
+     the paths in OLD_REV */
+
+  qsort(moves->elts, moves->nelts, moves->elt_size,
+        svn_sort_compare_paths);
+
+  for (i = 0; i < deletions->nelts; ++i)
+    {
+      const char *deleted_path = APR_ARRAY_IDX(deletions, i, const char*);
+      int closest_move_idx
+        = svn_sort__bsearch_lower_bound(deleted_path, moves,
+                                        svn_sort_compare_paths);
+
+      if (closest_move_idx < moves->nelts)
+        {
+          svn_sort__item_t *closest_move_item
+            = &APR_ARRAY_IDX(moves, closest_move_idx, svn_sort__item_t);
+          const char *relpath
+            = svn_dirent_skip_ancestor(closest_move_item->key,
+                                       deleted_path);
+          if (relpath)
+            {
+              change_t *closed_move = closest_move_item->value;
+              APR_ARRAY_IDX(deletions, i, const char*)
+                = svn_dirent_join(closed_move->info.copyfrom_path, relpath,
+                                  pool);
+            }
+        }
+    }
+
+  qsort(deletions->elts, deletions->nelts, deletions->elt_size,
+        svn_sort_compare_paths);
+
+  /* The _same_ source paths must never occur more than once in any move 
+     since our base revision. */
+
+  for (i = 0; moves->nelts; ++i)
+    SVN_ERR(check_for_duplicate_move_source (source_paths,
+                          APR_ARRAY_IDX(moves, i, svn_sort__item_t).value));
+
+  for (revision = txn_id->revision + 1; revision <= old_rev; ++revision)
+    {
+      apr_array_header_t *changes;
+      change_t **changes_p;
+
+      svn_pool_clear(iter_pool);
+      svn_fs_x__get_changes(&changes, fs, revision, iter_pool);
+
+      changes_p = (change_t **)&changes->elts;
+      for (i = 0; i < changes->nelts; ++i)
+        SVN_ERR(check_for_duplicate_move_source(source_paths, changes_p[i]));
+    }
+
+  /* The move source paths must been deleted in this txn. */
+
+  for (i = 0; i < moves->nelts; ++i)
+    {
+      change_t *change = APR_ARRAY_IDX(moves, i, svn_sort__item_t).value;
+
+      /* there must be a deletion of move's copy-from path
+         (or any of its parents) */
+
+      int closest_deletion_idx
+        = svn_sort__bsearch_lower_bound(change->info.copyfrom_path, deletions,
+                                        svn_sort_compare_paths);
+      if (closest_deletion_idx < deletions->nelts)
+        {
+          const char *closest_deleted_path
+            = APR_ARRAY_IDX(deletions, closest_deletion_idx, const char *);
+          if (!svn_dirent_is_ancestor(closest_deleted_path,
+                                      change->info.copyfrom_path))
+            return svn_error_createf(SVN_ERR_FS_INCOMPLETE_MOVE, NULL,
+                        _("Path '%s' has been moved without being deleted"),
+                                     change->info.copyfrom_path);
+        }
+    }
+
+  svn_pool_destroy(iter_pool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton used for commit_body below. */
 struct commit_baton {
   svn_revnum_t *new_rev_p;
@@ -2846,6 +3040,7 @@ commit_body(void *baton, apr_pool_t *poo
   apr_array_header_t *txnprop_list;
   svn_prop_t prop;
   const svn_fs_x__id_part_t *txn_id = svn_fs_x__txn_get_id(cb->txn);
+  apr_hash_t *changed_paths;
 
   /* Get the current youngest revision. */
   SVN_ERR(svn_fs_x__youngest_rev(&old_rev, cb->fs, pool));
@@ -2862,6 +3057,13 @@ commit_body(void *baton, apr_pool_t *poo
      discovered locks. */
   SVN_ERR(verify_locks(cb->fs, txn_id, pool));
 
+  /* we need the changes list for verification as well as for writing it
+     to the final rev file */
+  SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
+                                      pool));
+
+  SVN_ERR(verify_moves(cb->fs, txn_id, old_rev, changed_paths, pool));
+
   /* We are going to be one better than this puny old revision. */
   new_rev = old_rev + 1;
 
@@ -2879,7 +3081,8 @@ commit_body(void *baton, apr_pool_t *poo
 
   /* Write the changed-path information. */
   SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
-                                        cb->fs, txn_id, pool));
+                                        cb->fs, txn_id, changed_paths,
+                                        new_rev, pool));
 
   SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
   SVN_ERR(svn_io_file_close(proto_file, pool));

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/transaction.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_x/tree.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_x/tree.c Tue Oct 15 23:44:41 2013
@@ -132,6 +132,12 @@ static svn_error_t *make_txn_root(svn_fs
                                   apr_uint32_t flags,
                                   apr_pool_t *pool);
 
+static svn_error_t *x_closest_copy(svn_fs_root_t **root_p,
+                                   const char **path_p,
+                                   svn_fs_root_t *root,
+                                   const char *path,
+                                   apr_pool_t *pool);
+
 
 /*** Node Caching ***/
 
@@ -2330,15 +2336,89 @@ x_same_p(svn_boolean_t *same_p,
   return SVN_NO_ERROR;
 }
 
+/* Type to select the various behavioral modes of copy_helper.
+ */
+typedef enum copy_type_t
+{
+  /* add without history */
+  copy_type_plain_add,
+
+  /* add with history */
+  copy_type_add_with_history,
+
+  /* move (always with history) */
+  copy_type_move
+} copy_type_t;
+
+/* Set CHANGES to TRUE if PATH in ROOT is unchanged in REVISION if the
+   same files system.  If the content is identical, parent path copies and
+   deletions still count as changes.  Use POOL for temporary allocations.
+   Not that we will return an error if PATH does not exist in ROOT or
+   REVISION- */
+static svn_error_t *
+is_changed_node(svn_boolean_t *changed,
+                svn_fs_root_t *root,
+                const char *path,
+                svn_revnum_t revision,
+                apr_pool_t *pool)
+{
+  dag_node_t *node, *rev_node;
+  svn_fs_root_t *rev_root;
+  svn_fs_root_t *copy_from_root1, *copy_from_root2;
+  const char *copy_from_path1, *copy_from_path2;
+
+  SVN_ERR(svn_fs_x__revision_root(&rev_root, root->fs, revision, pool));
+
+  /* Get the NODE for FROM_PATH in FROM_ROOT.*/
+  SVN_ERR(get_dag(&node, root, path, TRUE, pool));
+  SVN_ERR(get_dag(&rev_node, rev_root, path, TRUE, pool));
+
+  /* different ID -> got changed */
+  if (!svn_fs_x__id_eq(svn_fs_x__dag_get_id(node),
+                       svn_fs_x__dag_get_id(rev_node)))
+    {
+      *changed = TRUE;
+       return SVN_NO_ERROR;
+    }
+
+  /* same node. might still be a lazy copy with separate history */
+  SVN_ERR(x_closest_copy(&copy_from_root1, &copy_from_path1, root,
+                         path, pool));
+  SVN_ERR(x_closest_copy(&copy_from_root2, &copy_from_path2, rev_root,
+                         path, pool));
+
+  if (copy_from_root1 == NULL && copy_from_root2 == NULL)
+    {
+      /* never copied -> same line of history */
+      *changed = FALSE;
+    }
+  else if (copy_from_root1 != NULL && copy_from_root2 != NULL)
+    {
+      /* both got copied. At the same time & location? */
+      *changed = (copy_from_root1->rev != copy_from_root2->rev)
+                 || strcmp(copy_from_path1, copy_from_path2);
+    }
+  else
+    {
+      /* one is a copy while the other one is not
+       * -> different lines of history */
+      *changed = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Copy the node at FROM_PATH under FROM_ROOT to TO_PATH under
-   TO_ROOT.  If PRESERVE_HISTORY is set, then the copy is recorded in
-   the copies table.  Perform temporary allocations in POOL. */
+   TO_ROOT.  COPY_TYPE determines whether then the copy is recorded in
+   the copies table and whether it is being marked as a move.
+   Perform temporary allocations in POOL. */
 static svn_error_t *
 copy_helper(svn_fs_root_t *from_root,
             const char *from_path,
             svn_fs_root_t *to_root,
             const char *to_path,
-            svn_boolean_t preserve_history,
+            copy_type_t copy_type,
             apr_pool_t *pool)
 {
   dag_node_t *from_node;
@@ -2355,11 +2435,48 @@ copy_helper(svn_fs_root_t *from_root,
        _("Cannot copy between two different filesystems ('%s' and '%s')"),
        from_root->fs->path, to_root->fs->path);
 
+  /* more things that we can't do ATM */
   if (from_root->is_txn_root)
     return svn_error_create
       (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
        _("Copy from mutable tree not currently supported"));
 
+  if (! to_root->is_txn_root)
+    return svn_error_create
+      (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+       _("Copy immutable tree not supported"));
+
+  /* move support comes with a number of conditions ... */
+  if (copy_type == copy_type_move)
+    {
+      /* if we don't copy from the TXN's base rev, check that the path has
+         not been touched in that revision range */
+      if (from_root->rev != txn_id->revision)
+        {
+          svn_boolean_t changed = TRUE;
+          svn_error_t *err = is_changed_node(&changed, from_root,
+                                             from_path, txn_id->revision,
+                                             pool);
+
+          /* Only "not found" is considered to be caused by out-of-date-ness.
+             Everything else means something got very wrong ... */
+          if (err && err->apr_err != SVN_ERR_FS_NOT_FOUND)
+            return svn_error_trace(err);
+
+          /* here error means "out of data" */
+          if (err || changed)
+            {
+              svn_error_clear(err);
+              return svn_error_create(SVN_ERR_FS_OUT_OF_DATE, NULL,
+                                      _("Move-from node is out-of-date"));
+            }
+
+          /* always move from the txn's base rev */
+          SVN_ERR(svn_fs_x__revision_root(&from_root, from_root->fs,
+                                          txn_id->revision, pool));
+        }
+    }
+
   /* Get the NODE for FROM_PATH in FROM_ROOT.*/
   SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));
 
@@ -2396,13 +2513,19 @@ copy_helper(svn_fs_root_t *from_root,
          operation is a replacement, not an addition. */
       if (to_parent_path->node)
         {
-          kind = svn_fs_path_change_replace;
+          kind = copy_type == copy_type_move
+               ? svn_fs_path_change_movereplace
+               : svn_fs_path_change_replace;
+
           SVN_ERR(svn_fs_x__dag_get_mergeinfo_count(&mergeinfo_start,
                                                     to_parent_path->node));
         }
       else
         {
-          kind = svn_fs_path_change_add;
+          kind = copy_type == copy_type_move
+               ? svn_fs_path_change_move
+               : svn_fs_path_change_add;
+
           mergeinfo_start = 0;
         }
 
@@ -2418,12 +2541,12 @@ copy_helper(svn_fs_root_t *from_root,
       SVN_ERR(svn_fs_x__dag_copy(to_parent_path->parent->node,
                                  to_parent_path->entry,
                                  from_node,
-                                 preserve_history,
+                                 copy_type != copy_type_plain_add,
                                  from_root->rev,
                                  from_canonpath,
                                  txn_id, pool));
 
-      if (kind == svn_fs_path_change_replace)
+      if (kind != svn_fs_path_change_add)
         SVN_ERR(dag_node_cache_invalidate(to_root,
                                           parent_path_path(to_parent_path,
                                                            pool), pool));
@@ -2477,7 +2600,7 @@ x_copy(svn_fs_root_t *from_root,
                                      to_root,
                                      svn_fs__canonicalize_abspath(to_path,
                                                                   pool),
-                                     TRUE, pool));
+                                     copy_type_add_with_history, pool));
 }
 
 
@@ -2495,7 +2618,27 @@ x_revision_link(svn_fs_root_t *from_root
 
   path = svn_fs__canonicalize_abspath(path, pool);
   return svn_error_trace(copy_helper(from_root, path, to_root, path,
-                                     FALSE, pool));
+                                     copy_type_plain_add, pool));
+}
+
+
+/* Create a copy of FROM_PATH in FROM_ROOT named TO_PATH in TO_ROOT and mark
+   it as a Move.  If FROM_PATH is a directory, copy it recursively. 
+   Temporary allocations are from POOL.*/
+static svn_error_t *
+x_move(svn_fs_root_t *from_root,
+       const char *from_path,
+       svn_fs_root_t *to_root,
+       const char *to_path,
+       apr_pool_t *pool)
+{
+  return svn_error_trace(copy_helper(from_root,
+                                     svn_fs__canonicalize_abspath(from_path,
+                                                                  pool),
+                                     to_root,
+                                     svn_fs__canonicalize_abspath(to_path,
+                                                                  pool),
+                                     copy_type_move, pool));
 }
 
 
@@ -4061,6 +4204,9 @@ static root_vtable_t root_vtable = {
   x_node_origin_rev,
   x_node_created_path,
   x_delete_node,
+  x_copy,
+  x_revision_link,
+  x_move,
   x_copied_from,
   x_closest_copy,
   x_node_prop,
@@ -4070,8 +4216,6 @@ static root_vtable_t root_vtable = {
   x_dir_entries,
   x_dir_optimal_order,
   x_make_dir,
-  x_copy,
-  x_revision_link,
   x_file_length,
   x_file_checksum,
   x_file_contents,
@@ -4253,19 +4397,25 @@ verify_node(dag_node_t *node,
         {
           svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
           dag_node_t *child;
-          svn_revnum_t child_rev;
           apr_int64_t child_mergeinfo;
 
           svn_pool_clear(iterpool);
 
           /* Compute CHILD_REV. */
-          SVN_ERR(svn_fs_x__dag_get_node(&child, fs, dirent->id, iterpool));
-          SVN_ERR(svn_fs_x__dag_get_revision(&child_rev, child, iterpool));
-
-          if (child_rev == rev)
-            SVN_ERR(verify_node(child, rev, iterpool));
+          if (svn_fs_x__id_rev(dirent->id) == rev)
+            {
+              SVN_ERR(svn_fs_x__dag_get_node(&child, fs, dirent->id,
+                                             iterpool));
+              SVN_ERR(verify_node(child, rev, iterpool));
+              SVN_ERR(svn_fs_x__dag_get_mergeinfo_count(&child_mergeinfo,
+                                                        child));
+            }
+          else
+            {
+              SVN_ERR(svn_fs_x__get_mergeinfo_count(&child_mergeinfo, fs,
+                                                    dirent->id, iterpool));
+            }
 
-          SVN_ERR(svn_fs_x__dag_get_mergeinfo_count(&child_mergeinfo, child));
           children_mergeinfo += child_mergeinfo;
         }
 

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_x/util.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra/compat.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra/compat.c Tue Oct 15 23:44:41 2013
@@ -363,8 +363,9 @@ svn_ra__locations_from_log(svn_ra_sessio
      Notice that we always run on the youngest rev of the 3 inputs. */
   targets = apr_array_make(pool, 1, sizeof(const char *));
   APR_ARRAY_PUSH(targets, const char *) = path;
-  SVN_ERR(svn_ra_get_log2(session, targets, youngest, oldest, 0,
+  SVN_ERR(svn_ra_get_log3(session, targets, youngest, oldest, 0,
                           TRUE, FALSE, FALSE,
+                          svn_move_behavior_explicit_moves,
                           apr_array_make(pool, 0, sizeof(const char *)),
                           log_receiver, &lrb, pool));
 
@@ -585,8 +586,9 @@ svn_ra__location_segments_from_log(svn_r
      Notice that we always run on the youngest rev of the 3 inputs. */
   targets = apr_array_make(pool, 1, sizeof(const char *));
   APR_ARRAY_PUSH(targets, const char *) = path;
-  SVN_ERR(svn_ra_get_log2(session, targets, peg_revision, end_rev, 0,
+  SVN_ERR(svn_ra_get_log3(session, targets, peg_revision, end_rev, 0,
                           TRUE, FALSE, FALSE,
+                          svn_move_behavior_explicit_moves,
                           apr_array_make(pool, 0, sizeof(const char *)),
                           gls_log_receiver, &lrb, pool));
 
@@ -684,10 +686,11 @@ svn_ra__file_revs_from_log(svn_ra_sessio
   /* Accumulate revision metadata by walking the revisions
      backwards; this allows us to follow moves/copies
      correctly. */
-  SVN_ERR(svn_ra_get_log2(ra_session,
+  SVN_ERR(svn_ra_get_log3(ra_session,
                           condensed_targets,
                           end, start, 0, /* no limit */
                           TRUE, FALSE, FALSE,
+                          svn_move_behavior_explicit_moves,
                           NULL, fr_log_message_receiver, &lmb,
                           pool));
 
@@ -853,8 +856,9 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
 
   /* Examine the logs of SESSION's URL to find when DELETED_PATH was first
      deleted or replaced. */
-  SVN_ERR(svn_ra_get_log2(session, NULL, peg_revision, end_revision, 0,
+  SVN_ERR(svn_ra_get_log3(session, NULL, peg_revision, end_revision, 0,
                           TRUE, TRUE, FALSE,
+                          svn_move_behavior_explicit_moves,
                           apr_array_make(pool, 0, sizeof(char *)),
                           log_path_del_receiver, &log_path_deleted_baton,
                           pool));

Modified: subversion/branches/log-addressing/subversion/libsvn_ra/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra/deprecated.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra/deprecated.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra/deprecated.c Tue Oct 15 23:44:41 2013
@@ -292,6 +292,25 @@ svn_error_t *svn_ra_do_diff(svn_ra_sessi
                          versus_url, diff_editor, diff_baton, pool);
 }
 
+svn_error_t *svn_ra_get_log2(svn_ra_session_t *session,
+                             const apr_array_header_t *paths,
+                             svn_revnum_t start,
+                             svn_revnum_t end,
+                             int limit,
+                             svn_boolean_t discover_changed_paths,
+                             svn_boolean_t strict_node_history,
+                             svn_boolean_t include_merged_revisions,
+                             const apr_array_header_t *revprops,
+                             svn_log_entry_receiver_t receiver,
+                             void *receiver_baton,
+                             apr_pool_t *pool)
+{
+  return svn_ra_get_log3(session, paths, start, end, limit,
+                         discover_changed_paths, strict_node_history,
+                         include_merged_revisions, svn_move_behavior_no_moves,
+                         revprops, receiver, receiver_baton, pool);
+}
+
 svn_error_t *svn_ra_get_log(svn_ra_session_t *session,
                             const apr_array_header_t *paths,
                             svn_revnum_t start,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.c Tue Oct 15 23:44:41 2013
@@ -877,7 +877,7 @@ svn_error_t *svn_ra_do_diff3(svn_ra_sess
                                   diff_baton, pool);
 }
 
-svn_error_t *svn_ra_get_log2(svn_ra_session_t *session,
+svn_error_t *svn_ra_get_log3(svn_ra_session_t *session,
                              const apr_array_header_t *paths,
                              svn_revnum_t start,
                              svn_revnum_t end,
@@ -885,6 +885,7 @@ svn_error_t *svn_ra_get_log2(svn_ra_sess
                              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_log_entry_receiver_t receiver,
                              void *receiver_baton,
@@ -905,8 +906,8 @@ svn_error_t *svn_ra_get_log2(svn_ra_sess
 
   return session->vtable->get_log(session, paths, start, end, limit,
                                   discover_changed_paths, strict_node_history,
-                                  include_merged_revisions, revprops,
-                                  receiver, receiver_baton, pool);
+                                  include_merged_revisions, move_behavior,
+                                  revprops, receiver, receiver_baton, pool);
 }
 
 svn_error_t *svn_ra_check_path(svn_ra_session_t *session,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra/ra_loader.h Tue Oct 15 23:44:41 2013
@@ -194,6 +194,7 @@ typedef struct svn_ra__vtable_t {
                           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_log_entry_receiver_t receiver,
                           void *receiver_baton,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra/wrapper_template.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra/wrapper_template.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra/wrapper_template.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra/wrapper_template.h Tue Oct 15 23:44:41 2013
@@ -395,6 +395,7 @@ static svn_error_t *compat_get_log(void 
   return VTBL.get_log(session_baton, paths, start, end, 0, /* limit */
                       discover_changed_paths, strict_node_history,
                       FALSE, /* include_merged_revisions */
+                      svn_move_behavior_no_moves,
                       svn_compat_log_revprops_in(pool), /* revprops */
                       receiver2, receiver2_baton, pool);
 }

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_local/ra_plugin.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_local/ra_plugin.c Tue Oct 15 23:44:41 2013
@@ -989,6 +989,7 @@ svn_ra_local__get_log(svn_ra_session_t *
                       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_log_entry_receiver_t receiver,
                       void *receiver_baton,
@@ -1017,7 +1018,7 @@ svn_ra_local__get_log(svn_ra_session_t *
   receiver = log_receiver_wrapper;
   receiver_baton = &lb;
 
-  return svn_repos_get_logs4(sess->repos,
+  return svn_repos_get_logs5(sess->repos,
                              abs_paths,
                              start,
                              end,
@@ -1025,6 +1026,7 @@ svn_ra_local__get_log(svn_ra_session_t *
                              discover_changed_paths,
                              strict_node_history,
                              include_merged_revisions,
+                             move_behavior,
                              revprops,
                              NULL, NULL,
                              receiver,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_local/split_url.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_local/split_url.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_local/split_url.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_local/split_url.c Tue Oct 15 23:44:41 2013
@@ -39,6 +39,7 @@ svn_ra_local__split_URL(svn_repos_t **re
   const char *repos_dirent;
   const char *repos_root_dirent;
   svn_stringbuf_t *urlbuf;
+  apr_size_t root_end;
 
   SVN_ERR(svn_uri_get_dirent_from_file_url(&repos_dirent, URL, pool));
 
@@ -65,10 +66,17 @@ svn_ra_local__split_URL(svn_repos_t **re
                    "/",
                    svn_dirent_skip_ancestor(repos_root_dirent, repos_dirent),
                    (const char *)NULL); */
-  *fs_path = &repos_dirent[strlen(repos_root_dirent)];
-
-  if (**fs_path == '\0')
+  root_end = strlen(repos_root_dirent);
+  if (! repos_dirent[root_end])
     *fs_path = "/";
+  else if (repos_dirent[root_end] == '/')
+    *fs_path = &repos_dirent[root_end];
+  else
+    {
+      /* On Windows "C:/" is the parent directory of "C:/dir" */
+      *fs_path = &repos_dirent[root_end-1];
+      SVN_ERR_ASSERT((*fs_path)[0] == '/');
+    }
 
   /* Remove the path components after the root dirent from the original URL,
      to get a URL to the repository root.

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/commit.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/commit.c Tue Oct 15 23:44:41 2013
@@ -1933,7 +1933,18 @@ add_file(const char *path,
 
       if (handler->sline.code != 404)
         {
-          return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
+          if (handler->sline.code != 200)
+            {
+              svn_error_t *err;
+
+              err = svn_ra_serf__error_on_status(handler->sline,
+                                                 handler->path,
+                                                 handler->location);
+
+              SVN_ERR(err);
+            }
+
+          return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
                                    _("File '%s' already exists"), path);
         }
     }
@@ -2168,8 +2179,8 @@ close_file(void *file_baton,
     {
       proppatch_context_t *proppatch;
 
-      proppatch = apr_pcalloc(ctx->pool, sizeof(*proppatch));
-      proppatch->pool = ctx->pool;
+      proppatch = apr_pcalloc(scratch_pool, sizeof(*proppatch));
+      proppatch->pool = scratch_pool;
       proppatch->relpath = ctx->relpath;
       proppatch->path = ctx->url;
       proppatch->commit = ctx->commit;
@@ -2177,7 +2188,7 @@ close_file(void *file_baton,
       proppatch->removed_props = ctx->removed_props;
       proppatch->base_revision = ctx->base_revision;
 
-      SVN_ERR(proppatch_resource(proppatch, ctx->commit, ctx->pool));
+      SVN_ERR(proppatch_resource(proppatch, ctx->commit, scratch_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/log.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/log.c Tue Oct 15 23:44:41 2013
@@ -76,6 +76,7 @@ typedef struct log_context_t {
   svn_boolean_t 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;
   int nest_level; /* used to track mergeinfo nesting levels */
   int count; /* only incremented when nest_level == 0 */
@@ -451,6 +452,14 @@ create_log_body(serf_bucket_t **body_bkt
                                    alloc);
     }
 
+  if (log_ctx->move_behavior != svn_move_behavior_no_moves)
+    {
+      svn_ra_serf__add_tag_buckets(buckets,
+                                   "S:move-behavior",
+                                   apr_ltoa(pool, log_ctx->move_behavior),
+                                   alloc);
+    }
+
   if (log_ctx->revprops)
     {
       int i;
@@ -507,6 +516,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
                      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_log_entry_receiver_t receiver,
                      void *receiver_baton,
@@ -532,6 +542,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
   log_ctx->changed_paths = discover_changed_paths;
   log_ctx->strict_node_history = strict_node_history;
   log_ctx->include_merged_revisions = include_merged_revisions;
+  log_ctx->move_behavior = move_behavior;
   log_ctx->revprops = revprops;
   log_ctx->nest_level = 0;
 

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/ra_serf.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/ra_serf.h Tue Oct 15 23:44:41 2013
@@ -429,6 +429,10 @@ typedef struct svn_ra_serf__handler_t {
      enabled. */
   svn_boolean_t custom_accept_encoding;
 
+  /* If TRUE then default DAV: capabilities request headers is not configured
+     for request. */
+  svn_boolean_t no_dav_headers;
+
   /* Has the request/response been completed?  */
   svn_boolean_t done;
 
@@ -1494,6 +1498,7 @@ svn_ra_serf__get_log(svn_ra_session_t *s
                      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_log_entry_receiver_t receiver,
                      void *receiver_baton,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/update.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/update.c Tue Oct 15 23:44:41 2013
@@ -1574,6 +1574,7 @@ fetch_file(report_context_t *ctx, report
           handler->session = ctx->sess;
 
           handler->custom_accept_encoding = TRUE;
+          handler->no_dav_headers = TRUE;
           handler->header_delegate = headers_fetch;
           handler->header_delegate_baton = fetch_ctx;
 
@@ -3705,6 +3706,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
           handler->session = session;
 
           handler->custom_accept_encoding = TRUE;
+          handler->no_dav_headers = TRUE;
           handler->header_delegate = headers_fetch;
           handler->header_delegate_baton = stream_ctx;
 

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_serf/util.c Tue Oct 15 23:44:41 2013
@@ -705,6 +705,9 @@ apr_status_t svn_ra_serf__handle_client_
  *
  * If CONTENT_TYPE is not-NULL, it will be sent as the Content-Type header.
  *
+ * If DAV_HEADERS is non-zero, it will add standard DAV capabilites headers
+ * to request.
+ *
  * REQUEST_POOL should live for the duration of the request. Serf will
  * construct this and provide it to the request_setup callback, so we
  * should just use that one.
@@ -717,6 +720,7 @@ setup_serf_req(serf_request_t *request,
                const char *method, const char *url,
                serf_bucket_t *body_bkt, const char *content_type,
                const char *accept_encoding,
+               svn_boolean_t dav_headers,
                apr_pool_t *request_pool,
                apr_pool_t *scratch_pool)
 {
@@ -783,12 +787,15 @@ setup_serf_req(serf_request_t *request,
       serf_bucket_headers_setn(*hdrs_bkt, "Accept-Encoding", accept_encoding);
     }
 
-  /* These headers need to be sent with every request; see issue #3255
-     ("mod_dav_svn does not pass client capabilities to start-commit
-     hooks") for why. */
-  serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
-  serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_MERGEINFO);
-  serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
+  /* These headers need to be sent with every request except GET; see
+     issue #3255 ("mod_dav_svn does not pass client capabilities to
+     start-commit hooks") for why. */
+  if (dav_headers)
+    {
+      serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
+      serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_MERGEINFO);
+      serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2241,7 +2248,8 @@ setup_request(serf_request_t *request,
   SVN_ERR(setup_serf_req(request, req_bkt, &headers_bkt,
                          handler->session, handler->method, handler->path,
                          body_bkt, handler->body_type, accept_encoding,
-                         request_pool, scratch_pool));
+                         !handler->no_dav_headers, request_pool,
+                         scratch_pool));
 
   if (handler->header_delegate)
     {
@@ -2251,7 +2259,7 @@ setup_request(serf_request_t *request,
                                        request_pool));
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
 /* Implements the serf_request_setup_t interface (which sets up both a

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/client.c Tue Oct 15 23:44:41 2013
@@ -561,14 +561,42 @@ static svn_error_t *parse_url(const char
   return SVN_NO_ERROR;
 }
 
+/* This structure is used as a baton for the pool cleanup function to
+   store tunnel parameters used by the close-tunnel callback. */
+struct tunnel_data_t {
+  void *tunnel_context;
+  void *tunnel_baton;
+  const char *tunnel_name;
+  const char *user;
+  const char *hostname;
+  int port;
+  svn_ra_close_tunnel_func_t close_tunnel;
+};
+
+/* Pool cleanup function that invokes the close-tunel callback. */
+static apr_status_t close_tunnel_cleanup(void *baton)
+{
+  const struct tunnel_data_t *const td = baton;
+  svn_error_t *const err =
+    svn_error_root_cause(td->close_tunnel(td->tunnel_context, td->tunnel_baton,
+                                          td->tunnel_name, td->user,
+                                          td->hostname, td->port));
+  const apr_status_t ret = (err ? err->apr_err : 0);
+  svn_error_clear(err);
+  return ret;
+}
+
 /* Open a session to URL, returning it in *SESS_P, allocating it in POOL.
    URI is a parsed version of URL.  CALLBACKS and CALLBACKS_BATON
-   are provided by the caller of ra_svn_open. If tunnel_argv is non-null,
-   it points to a program argument list to use when invoking the tunnel agent.
+   are provided by the caller of ra_svn_open. If TUNNEL_NAME is not NULL,
+   it is the name of the tunnel type parsed from the URL scheme.
+   If TUNNEL_ARGV is not NULL, it points to a program argument list to use
+   when invoking the tunnel agent.
 */
 static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
                                  const char *url,
                                  const apr_uri_t *uri,
+                                 const char *tunnel_name,
                                  const char **tunnel_argv,
                                  const svn_ra_callbacks2_t *callbacks,
                                  void *callbacks_baton,
@@ -583,19 +611,52 @@ static svn_error_t *open_session(svn_ra_
 
   sess = apr_palloc(pool, sizeof(*sess));
   sess->pool = pool;
-  sess->is_tunneled = (tunnel_argv != NULL);
+  sess->is_tunneled = (tunnel_name != NULL);
   sess->url = apr_pstrdup(pool, url);
   sess->user = uri->user;
   sess->hostname = uri->hostname;
   sess->realm_prefix = apr_psprintf(pool, "<svn://%s:%d>", uri->hostname,
                                     uri->port);
+  sess->tunnel_name = tunnel_name;
   sess->tunnel_argv = tunnel_argv;
   sess->callbacks = callbacks;
   sess->callbacks_baton = callbacks_baton;
   sess->bytes_read = sess->bytes_written = 0;
 
-  if (tunnel_argv)
-    SVN_ERR(make_tunnel(tunnel_argv, &conn, pool));
+  if (tunnel_name)
+    {
+      if (tunnel_argv)
+        SVN_ERR(make_tunnel(tunnel_argv, &conn, pool));
+      else
+        {
+          void *tunnel_context;
+          apr_file_t *request;
+          apr_file_t *response;
+          SVN_ERR(callbacks->open_tunnel_func(
+                      &request, &response, &tunnel_context,
+                      callbacks->tunnel_baton, tunnel_name,
+                      uri->user, uri->hostname, uri->port,
+                      pool));
+          if (callbacks->close_tunnel_func)
+            {
+              struct tunnel_data_t *const td = apr_palloc(pool, sizeof(*td));
+              td->tunnel_context = tunnel_context;
+              td->tunnel_baton = callbacks->tunnel_baton;
+              td->tunnel_name = apr_pstrdup(pool, tunnel_name);
+              td->user = apr_pstrdup(pool, uri->user);
+              td->hostname = apr_pstrdup(pool, uri->hostname);
+              td->port = uri->port;
+              td->close_tunnel = callbacks->close_tunnel_func;
+              apr_pool_cleanup_register(pool, td, close_tunnel_cleanup,
+                                        apr_pool_cleanup_null);
+            }
+
+          conn = svn_ra_svn_create_conn3(NULL, response, request,
+                                         SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
+                                         0, 0, pool);
+          SVN_ERR(svn_ra_svn__skip_leading_garbage(conn, pool));
+        }
+    }
   else
     {
       SVN_ERR(make_connection(uri->hostname, uri->port, &sock, pool));
@@ -738,7 +799,14 @@ static svn_error_t *ra_svn_open(svn_ra_s
 
   parse_tunnel(url, &tunnel, pool);
 
-  if (tunnel)
+  /* Use the default tunnel implementation if we got a tunnel name,
+     but either do not have tunnel handler callbacks installed, or
+     the handlers don't like the tunnel name. */
+  if (tunnel
+      && (!callbacks->open_tunnel_func
+          || (callbacks->check_tunnel_func && callbacks->open_tunnel_func
+              && !callbacks->check_tunnel_func(callbacks->tunnel_baton,
+                                               tunnel))))
     SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv, config,
                               pool));
   else
@@ -755,7 +823,7 @@ static svn_error_t *ra_svn_open(svn_ra_s
 
   /* We open the session in a subpool so we can get rid of it if we
      reparent with a server that doesn't support reparenting. */
-  SVN_ERR(open_session(&sess, url, &uri, tunnel_argv,
+  SVN_ERR(open_session(&sess, url, &uri, tunnel, tunnel_argv,
                        callbacks, callback_baton, sess_pool));
   session->priv = sess;
 
@@ -791,7 +859,7 @@ static svn_error_t *ra_svn_reparent(svn_
   sess_pool = svn_pool_create(ra_session->pool);
   err = parse_url(url, &uri, sess_pool);
   if (! err)
-    err = open_session(&new_sess, url, &uri, sess->tunnel_argv,
+    err = open_session(&new_sess, url, &uri, sess->tunnel_name, sess->tunnel_argv,
                        sess->callbacks, sess->callbacks_baton, sess_pool);
   /* We destroy the new session pool on error, since it is allocated in
      the main session pool. */
@@ -1487,6 +1555,7 @@ perform_ra_svn_log(svn_error_t **outer_e
                    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_log_entry_receiver_t receiver,
                    void *receiver_baton,
@@ -1536,11 +1605,13 @@ perform_ra_svn_log(svn_error_t **outer_e
           else
             want_custom_revprops = TRUE;
         }
-      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!))"));
+      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!)n)",
+                                      (apr_uint64_t) move_behavior));
     }
   else
     {
-      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!w())", "all-revprops"));
+      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!w()n)", "all-revprops",
+                                      (apr_uint64_t) move_behavior));
 
       want_author = TRUE;
       want_date = TRUE;
@@ -1712,6 +1783,7 @@ ra_svn_log(svn_ra_session_t *session,
            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_log_entry_receiver_t receiver,
            void *receiver_baton, apr_pool_t *pool)
@@ -1726,7 +1798,7 @@ ra_svn_log(svn_ra_session_t *session,
                                            discover_changed_paths,
                                            strict_node_history,
                                            include_merged_revisions,
-                                           revprops,
+                                           move_behavior, revprops,
                                            receiver, receiver_baton,
                                            pool));
   return svn_error_trace(

Propchange: subversion/branches/log-addressing/subversion/libsvn_ra_svn/deprecated.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/marshal.c Tue Oct 15 23:44:41 2013
@@ -1017,7 +1017,7 @@ static svn_error_t *read_string(svn_ra_s
 
 /* Given the first non-whitespace character FIRST_CHAR, read an item
  * into the already allocated structure ITEM.  LEVEL should be set
- * to 0 for the first call and is used to enforce a recurssion limit
+ * to 0 for the first call and is used to enforce a recursion limit
  * on the parser. */
 static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                               svn_ra_svn_item_t *item, char first_char,

Modified: subversion/branches/log-addressing/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_ra_svn/protocol?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/log-addressing/subversion/libsvn_ra_svn/protocol Tue Oct 15 23:44:41 2013
@@ -382,11 +382,13 @@ second place for auth-request point as n
                 [ end-rev:number ] changed-paths:bool strict-node:bool
                 ? limit:number
                 ? include-merged-revisions:bool
-                all-revprops | revprops ( revprop:string ... ) )
+                all-revprops | revprops ( revprop:string ... )
+                ? move-behavior:number )
     Before sending response, server sends log entries, ending with "done".
     If a client does not want to specify a limit, it should send 0 as the
     limit parameter.  rev-props excludes author, date, and log; they are
     sent separately for backwards-compatibility.
+    Move-behavior is encoded like enum svn_move_behavior_t.
     log-entry: ( ( change:changed-path-entry ... ) rev:number
                  [ author:string ] [ date:string ] [ message:string ]
                  ? has-children:bool invalid-revnum:bool