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(©_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(©_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