You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/05/22 19:44:38 UTC

svn commit: r1485309 - in /subversion/branches/move-tracking-1/subversion: include/ libsvn_client/ libsvn_fs/ libsvn_fs_base/ libsvn_fs_fs/ libsvn_repos/

Author: julianfoad
Date: Wed May 22 17:44:37 2013
New Revision: 1485309

URL: http://svn.apache.org/r1485309
Log:
On the 'move-tracking-1' branch: start to transmit some moves to the repo
and store them as such in FSFS.
 
  Client side:
    + Make 'move URL URL' send a move to the RA layer.

  Network:
    + In RA-local (only), implement sending a move using the 'copy' method
      with copy-from-rev = -1.

  Server side:
    + In the repos layer, implement storing a move using the 'copy' method
      with copy-from-rev = -1.
    + Add a FS layer 'move' method.
    + Add a FSFS 'move' method, that keeps copy-id the same. (In all other
      respects it's still recorded as a 'copy' and a 'delete'.)

* subversion/libsvn_client/copy.c
  (path_driver_cb_func): Process moves as moves, and don't process deleted
    paths separately.
  (repos_to_repos_copy): Set the copy-from source revision to -1 for moves,
    and don't have path_driver_cb_func() processes those source paths.

* subversion/include/svn_delta.h
  (svn_delta_editor_t): Document that the editor can now support a 'move'
    operation, using the 'add' methods with copy-from-rev = -1.

* subversion/include/svn_repos.h
  (svn_repos_get_commit_editor5): Document that this editor supports 'move'.

* subversion/libsvn_repos/commit.c
  (add_file_or_directory): Handle copy-from-rev == -1 as a move.

* subversion/include/svn_fs.h,
  subversion/libsvn_fs/fs-loader.c
  (svn_fs_move): New function.

* subversion/libsvn_fs/fs-loader.h
  (root_vtable_t): Add a new method, 'move'.

* subversion/libsvn_fs_base/tree.c
  (root_vtable): Add a dummy (null) entry for 'move'.

* subversion/libsvn_fs_fs/tree.c
  (fs_move): New function.
  (root_vtable): Add it.

Modified:
    subversion/branches/move-tracking-1/subversion/include/svn_delta.h
    subversion/branches/move-tracking-1/subversion/include/svn_fs.h
    subversion/branches/move-tracking-1/subversion/include/svn_repos.h
    subversion/branches/move-tracking-1/subversion/libsvn_client/copy.c
    subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.c
    subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.h
    subversion/branches/move-tracking-1/subversion/libsvn_fs_base/tree.c
    subversion/branches/move-tracking-1/subversion/libsvn_fs_fs/tree.c
    subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c

Modified: subversion/branches/move-tracking-1/subversion/include/svn_delta.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/include/svn_delta.h?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/include/svn_delta.h (original)
+++ subversion/branches/move-tracking-1/subversion/include/svn_delta.h Wed May 22 17:44:37 2013
@@ -890,6 +890,11 @@ typedef struct svn_delta_editor_t
    * copy), and the origin of the copy may be recorded as
    * @a copyfrom_path under @a copyfrom_revision.
    *
+   * If @a copyfrom_revision is SVN_INVALID_REVNUM, then this is a move
+   * rather than a copy, and @a copyfrom_path identifies the source node
+   * of the move by reference to a path within the current tree being
+   * edited.  This implicitly deletes the node which was at the source path.
+   *
    * Allocations for the returned @a child_baton should be performed in
    * @a result_pool. It is also typical to (possibly) save this pool for
    * later usage by @c close_directory.
@@ -962,9 +967,7 @@ typedef struct svn_delta_editor_t
    * store a baton for this new file in @a **file_baton; whatever value
    * it stores there should be passed through to @c apply_textdelta.
    *
-   * If @a copyfrom_path is non-@c NULL, this add has history (i.e., is a
-   * copy), and the origin of the copy may be recorded as
-   * @a copyfrom_path under @a copyfrom_revision.
+   * @a copyfrom_path and @a copyfrom_revision are as for @c add_directory.
    *
    * Allocations for the returned @a file_baton should be performed in
    * @a result_pool. It is also typical to save this pool for later usage

Modified: subversion/branches/move-tracking-1/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/include/svn_fs.h?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/include/svn_fs.h (original)
+++ subversion/branches/move-tracking-1/subversion/include/svn_fs.h Wed May 22 17:44:37 2013
@@ -1798,6 +1798,22 @@ svn_fs_copy(svn_fs_root_t *from_root,
             apr_pool_t *pool);
 
 
+/** Move @a from_path to @a to_path in @a root.
+ *
+ * This is similar to copy and delete, except the node will keep the
+ * same node identity (node id + copy id).
+ *
+ * @a root must be the root of a transaction.
+ *
+ * Do any necessary temporary allocation in @a pool.
+ */
+svn_error_t *
+svn_fs_move(svn_fs_root_t *root,
+            const char *from_path,
+            const char *to_path,
+            apr_pool_t *pool);
+
+
 /** Like svn_fs_copy(), but doesn't record copy history, and preserves
  * the PATH.  You cannot use svn_fs_copied_from() later to find out
  * where this copy came from.

Modified: subversion/branches/move-tracking-1/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/include/svn_repos.h?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/include/svn_repos.h (original)
+++ subversion/branches/move-tracking-1/subversion/include/svn_repos.h Wed May 22 17:44:37 2013
@@ -1410,6 +1410,8 @@ svn_repos_replay(svn_fs_root_t *root,
  * NULL).  Callers who supply their own transactions are responsible
  * for cleaning them up (either by committing them, or aborting them).
  *
+ * @since 1.9, the editor supports moves (indicated by copy-from-rev=-1).
+ *
  * @since New in 1.5.
  *
  * @note Yes, @a repos_url is a <em>decoded</em> URL.  We realize

Modified: subversion/branches/move-tracking-1/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_client/copy.c?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_client/copy.c Wed May 22 17:44:37 2013
@@ -603,9 +603,10 @@ path_driver_cb_func(void **dir_baton,
                     apr_pool_t *pool)
 {
   struct path_driver_cb_baton *cb_baton = callback_baton;
-  svn_boolean_t do_delete = FALSE, do_add = FALSE;
   path_driver_info_t *path_info = svn_hash_gets(cb_baton->action_hash, path);
 
+  SVN_ERR_ASSERT(! (path_info->resurrection && cb_baton->is_move));
+
   /* Initialize return value. */
   *dir_baton = NULL;
 
@@ -622,69 +623,35 @@ path_driver_cb_func(void **dir_baton,
                                              dir_baton);
     }
 
-  /* If this is a resurrection, we know the source and dest paths are
-     the same, and that our driver will only be calling us once.  */
-  if (path_info->resurrection)
-    {
-      /* If this is a move, we do nothing.  Otherwise, we do the copy.  */
-      if (! cb_baton->is_move)
-        do_add = TRUE;
-    }
-  /* Not a resurrection. */
-  else
-    {
-      /* If this is a move, we check PATH to see if it is the source
-         or the destination of the move. */
-      if (cb_baton->is_move)
-        {
-          if (strcmp(path_info->src_path, path) == 0)
-            do_delete = TRUE;
-          else
-            do_add = TRUE;
-        }
-      /* Not a move?  This must just be the copy addition. */
-      else
-        {
-          do_add = TRUE;
-        }
-    }
+  SVN_ERR(svn_path_check_valid(path, pool));
 
-  if (do_delete)
+  if (path_info->src_kind == svn_node_file)
     {
-      SVN_ERR(cb_baton->editor->delete_entry(path, SVN_INVALID_REVNUM,
-                                             parent_baton, pool));
+      void *file_baton;
+      SVN_ERR(cb_baton->editor->add_file(path, parent_baton,
+                                         path_info->src_url,
+                                         path_info->src_revnum,
+                                         pool, &file_baton));
+      if (path_info->mergeinfo)
+        SVN_ERR(cb_baton->editor->change_file_prop(file_baton,
+                                                   SVN_PROP_MERGEINFO,
+                                                   path_info->mergeinfo,
+                                                   pool));
+      SVN_ERR(cb_baton->editor->close_file(file_baton, NULL, pool));
     }
-  if (do_add)
+  else
     {
-      SVN_ERR(svn_path_check_valid(path, pool));
-
-      if (path_info->src_kind == svn_node_file)
-        {
-          void *file_baton;
-          SVN_ERR(cb_baton->editor->add_file(path, parent_baton,
-                                             path_info->src_url,
-                                             path_info->src_revnum,
-                                             pool, &file_baton));
-          if (path_info->mergeinfo)
-            SVN_ERR(cb_baton->editor->change_file_prop(file_baton,
-                                                       SVN_PROP_MERGEINFO,
-                                                       path_info->mergeinfo,
-                                                       pool));
-          SVN_ERR(cb_baton->editor->close_file(file_baton, NULL, pool));
-        }
-      else
-        {
-          SVN_ERR(cb_baton->editor->add_directory(path, parent_baton,
-                                                  path_info->src_url,
-                                                  path_info->src_revnum,
-                                                  pool, dir_baton));
-          if (path_info->mergeinfo)
-            SVN_ERR(cb_baton->editor->change_dir_prop(*dir_baton,
-                                                      SVN_PROP_MERGEINFO,
-                                                      path_info->mergeinfo,
-                                                      pool));
-        }
+      SVN_ERR(cb_baton->editor->add_directory(path, parent_baton,
+                                              path_info->src_url,
+                                              path_info->src_revnum,
+                                              pool, dir_baton));
+      if (path_info->mergeinfo)
+        SVN_ERR(cb_baton->editor->change_dir_prop(*dir_baton,
+                                                  SVN_PROP_MERGEINFO,
+                                                  path_info->mergeinfo,
+                                                  pool));
     }
+
   return SVN_NO_ERROR;
 }
 
@@ -849,7 +816,7 @@ repos_to_repos_copy(const apr_array_head
 
       /* Plop an INFO structure onto our array thereof. */
       info->src_url = pair->src_abspath_or_url;
-      info->src_revnum = pair->src_revnum;
+      info->src_revnum = is_move ? SVN_INVALID_REVNUM : pair->src_revnum;
       info->resurrection = FALSE;
       APR_ARRAY_PUSH(path_infos, path_driver_info_t *) = info;
     }
@@ -1122,15 +1089,13 @@ repos_to_repos_copy(const apr_array_head
         }
     }
 
-  /* Then our copy destinations and move sources (if any). */
+  /* Then our copy destinations. */
   for (i = 0; i < path_infos->nelts; i++)
     {
       path_driver_info_t *info = APR_ARRAY_IDX(path_infos, i,
                                                path_driver_info_t *);
 
       APR_ARRAY_PUSH(paths, const char *) = info->dst_path;
-      if (is_move && (! info->resurrection))
-        APR_ARRAY_PUSH(paths, const char *) = info->src_path;
     }
 
   SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,

Modified: subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.c?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.c Wed May 22 17:44:37 2013
@@ -1176,6 +1176,14 @@ svn_fs_copy(svn_fs_root_t *from_root, co
 }
 
 svn_error_t *
+svn_fs_move(svn_fs_root_t *root, const char *from_path,
+            const char *to_path, apr_pool_t *pool)
+{
+  SVN_ERR(svn_fs__path_valid(to_path, pool));
+  return svn_error_trace(root->vtable->move(root, from_path, to_path, pool));
+}
+
+svn_error_t *
 svn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root,
                      const char *path, apr_pool_t *pool)
 {

Modified: subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.h?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_fs/fs-loader.h Wed May 22 17:44:37 2013
@@ -320,6 +320,8 @@ typedef struct root_vtable_t
   svn_error_t *(*copy)(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_error_t *(*move)(svn_fs_root_t *root, const char *from_path,
+                       const char *to_path, apr_pool_t *pool);
   svn_error_t *(*revision_link)(svn_fs_root_t *from_root,
                                 svn_fs_root_t *to_root,
                                 const char *path,

Modified: subversion/branches/move-tracking-1/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_fs_base/tree.c?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_fs_base/tree.c Wed May 22 17:44:37 2013
@@ -5376,6 +5376,7 @@ static root_vtable_t root_vtable = {
   base_dir_entries,
   base_make_dir,
   base_copy,
+  NULL /* move */,
   base_revision_link,
   base_file_length,
   base_file_checksum,

Modified: subversion/branches/move-tracking-1/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_fs_fs/tree.c?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_fs_fs/tree.c Wed May 22 17:44:37 2013
@@ -2483,6 +2483,30 @@ fs_copy(svn_fs_root_t *from_root,
 }
 
 
+/* Move FROM_PATH to TO_PATH in ROOT.
+ *
+ * Temporary allocations are from POOL.
+ */
+static svn_error_t *
+fs_move(svn_fs_root_t *root,
+        const char *from_path,
+        const char *to_path,
+        apr_pool_t *pool)
+{
+  svn_fs_root_t *from_root;
+
+  SVN_ERR(check_newline(to_path, pool));
+  from_path = svn_fs__canonicalize_abspath(from_path, pool);
+  to_path = svn_fs__canonicalize_abspath(to_path, pool);
+
+  SVN_ERR(svn_fs_fs__revision_root(&from_root, root->fs, root->rev, pool));
+  SVN_ERR(fs_delete_node(root, from_path, pool));
+  SVN_ERR(copy_helper(from_root, from_path, root, to_path,
+                      FALSE /*preserve_history*/, pool));
+  return SVN_NO_ERROR;
+}
+
+
 /* Create a copy of FROM_PATH in FROM_ROOT named TO_PATH in TO_ROOT.
    If FROM_PATH is a directory, copy it recursively.  No history is
    preserved.  Temporary allocations are from POOL. */
@@ -3134,7 +3158,10 @@ typedef struct fs_history_data_t
   const char *path_hint;
   svn_revnum_t rev_hint;
 
-  /* FALSE until the first call to svn_fs_history_prev(). */
+  /* If true, this history object is being reported (or was or will be
+   * reported) by the prev() method.  (If false, the location described
+   * by this history object might still be found to be interesting and,
+   * if so, then a new object will be created to report it). */
   svn_boolean_t is_interesting;
 } fs_history_data_t;
 
@@ -3462,6 +3489,11 @@ fs_node_origin_rev(svn_revnum_t *revisio
 }
 
 
+/* Set *PREV_HISTORY to a description of the previous, potentially
+ * interesting, history location before HISTORY. If the location described
+ * is not actually interesting (for example, it is a copy but not a
+ * copy-root), then set its 'is_interesting' field to false.
+ */
 static svn_error_t *
 history_prev(svn_fs_history_t **prev_history,
              svn_fs_history_t *history,
@@ -3484,9 +3516,12 @@ history_prev(svn_fs_history_t **prev_his
   /* Initialize our return value. */
   *prev_history = NULL;
 
-  /* If our last history report left us hints about where to pickup
-     the chase, then our last report was on the destination of a
-     copy.  If we are crossing copies, start from those locations,
+  SVN_DBG(("history: %s@%ld (from %s@%ld)",
+           fhd->path, fhd->revision,
+           fhd->path_hint, fhd->rev_hint));
+  /* If our last history report left us hints about where to pick up
+     the chase, then our last report was on the destination of a copy
+     or move.  If we are crossing copies, start from those locations,
      otherwise, we're all done here.  */
   if (fhd->path_hint && SVN_IS_VALID_REVNUM(fhd->rev_hint))
     {
@@ -3506,6 +3541,7 @@ history_prev(svn_fs_history_t **prev_his
   node = parent_path->node;
   commit_path = svn_fs_fs__dag_get_created_path(node);
   SVN_ERR(svn_fs_fs__dag_get_revision(&commit_rev, node, scratch_pool));
+  SVN_DBG(("ppath.noderev=%s", svn_fs_fs__id_unparse(svn_fs_fs__dag_get_id(node), scratch_pool)->data));
 
   /* The Subversion filesystem is written in such a way that a given
      line of history may have at most one interesting history point
@@ -3514,7 +3550,7 @@ history_prev(svn_fs_history_t **prev_his
      source cannot be from the same revision as its destination.  So,
      if our history revision matches its node's commit revision, we
      know that ... */
-  if (revision == commit_rev)
+  if (revision == commit_rev || strcmp(path, commit_path) != 0)
     {
       if (! reported)
         {
@@ -3591,19 +3627,14 @@ history_prev(svn_fs_history_t **prev_his
 
   /* If we calculated a copy source path and revision, we'll make a
      'copy-style' history object. */
-  if (src_path && SVN_IS_VALID_REVNUM(src_rev))
+  if (src_path)
     {
-      svn_boolean_t retry = FALSE;
-
       /* It's possible for us to find a copy location that is the same
          as the history point we've just reported.  If that happens,
          we simply need to take another trip through this history
          search. */
-      if ((dst_rev == revision) && reported)
-        retry = TRUE;
-
       *prev_history = assemble_history(fs, apr_pstrdup(result_pool, path),
-                                       dst_rev, ! retry,
+                                       dst_rev, dst_rev != revision || ! reported,
                                        src_path, src_rev, result_pool);
     }
   else
@@ -4124,6 +4155,7 @@ static root_vtable_t root_vtable = {
   fs_dir_entries,
   fs_make_dir,
   fs_copy,
+  fs_move,
   fs_revision_link,
   fs_file_length,
   fs_file_checksum,

Modified: subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c?rev=1485309&r1=1485308&r2=1485309&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c Wed May 22 17:44:37 2013
@@ -284,12 +284,6 @@ add_file_or_directory(const char *path,
   full_path = svn_fspath__join(eb->base_path,
                                svn_relpath_canonicalize(path, pool), pool);
 
-  /* Sanity check. */
-  if (copy_path && (! SVN_IS_VALID_REVNUM(copy_revision)))
-    return svn_error_createf
-      (SVN_ERR_FS_GENERAL, NULL,
-       _("Got source path but no source revision for '%s'"), full_path);
-
   if (copy_path)
     {
       const char *fs_path;
@@ -325,17 +319,36 @@ add_file_or_directory(const char *path,
 
       fs_path = apr_pstrdup(subpool, copy_path + repos_url_len);
 
-      /* Now use the "fs_path" as an absolute path within the
-         repository to make the copy from. */
-      SVN_ERR(svn_fs_revision_root(&copy_root, eb->fs,
-                                   copy_revision, subpool));
-
-      /* Copy also requires (recursive) read access to the source */
-      required = svn_authz_read | (is_dir ? svn_authz_recursive : 0);
-      SVN_ERR(check_authz(eb, fs_path, copy_root, required, subpool));
+      /* Is this a copy or a move? */
+      if (SVN_IS_VALID_REVNUM(copy_revision))
+        {
+          /* Now use the "fs_path" as an absolute path within the
+             repository to make the copy from. */
+          SVN_ERR(svn_fs_revision_root(&copy_root, eb->fs,
+                                       copy_revision, subpool));
+
+          /* Copy also requires (recursive) read access to the source */
+          required = svn_authz_read | (is_dir ? svn_authz_recursive : 0);
+          SVN_ERR(check_authz(eb, fs_path, copy_root, required, subpool));
+
+          SVN_ERR(svn_fs_copy(copy_root, fs_path,
+                              eb->txn_root, full_path, subpool));
+        }
+      else
+        {
+          const char *from_parent_fs_path
+            = svn_fspath__dirname(fs_path, subpool);
+
+          /* Move also requires (recursive) write access to the source node
+             and write access to its parent directory. */
+          required = svn_authz_write | (is_dir ? svn_authz_recursive : 0);
+          SVN_ERR(check_authz(eb, fs_path, eb->txn_root, required, subpool));
+          SVN_ERR(check_authz(eb, from_parent_fs_path, eb->txn_root,
+                              svn_authz_write, subpool));
+
+          SVN_ERR(svn_fs_move(eb->txn_root, fs_path, full_path, subpool));
+        }
 
-      SVN_ERR(svn_fs_copy(copy_root, fs_path,
-                          eb->txn_root, full_path, subpool));
       was_copied = TRUE;
     }
   else