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/09/27 23:29:22 UTC

svn commit: r1527088 - /subversion/trunk/subversion/libsvn_fs_x/tree.c

Author: stefan2
Date: Fri Sep 27 21:29:22 2013
New Revision: 1527088

URL: http://svn.apache.org/r1527088
Log:
Sync FSX fs_move code with latest FSFS changes.

* subversion/libsvn_fs_x/tree.c
  (is_changed_node): new utility
  (copy_helper): allow moving from older revisions if there were
                 no intermittent changes

Modified:
    subversion/trunk/subversion/libsvn_fs_x/tree.c

Modified: subversion/trunk/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/tree.c?rev=1527088&r1=1527087&r2=1527088&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/tree.c Fri Sep 27 21:29:22 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 ***/
 
@@ -2344,6 +2350,65 @@ typedef enum copy_type_t
   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_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(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.  COPY_TYPE determines whether then the copy is recorded in
    the copies table and whether it is being marked as a move.
@@ -2381,10 +2446,36 @@ copy_helper(svn_fs_root_t *from_root,
       (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
        _("Copy immutable tree not supported"));
 
-  if (copy_type == copy_type_move && from_root->rev != txn_id->revision)
-    return svn_error_create
-      (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-       _("Move from non-HEAD revision not currently 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));
+        }
+    }
 
   /* Get the NODE for FROM_PATH in FROM_ROOT.*/
   SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));