Author: julianfoad
Date: Wed Oct 27 08:12:58 2010
New Revision: 1027851
URL: http://svn.apache.org/viewvc?rev=1027851&view=rev
Log:
Implement op_depth for copies, when SVN_WC__OP_DEPTH is defined. The test
"op-depth-test.c 1" now passes. Some other tests now fail, which may be due
to bugs in here and/or due to other code that doesn't yet support op_depth
properly.
* subversion/libsvn_wc/copy.c
(copy_versioned_node): New function. Uses svn_wc__db_op_copy_tree() for
same-WC copies, and the old code for cross-WC copies.
(svn_wc_copy3): Use copy_versioned_node() if SVN_WC__OP_DEPTH is defined.
* subversion/libsvn_wc/wc_db.h
(svn_wc__db_op_copy_tree): New function.
* subversion/libsvn_wc/wc_db.c
(op_depth_of, copy_nodes_rows, copy_actual_rows, copy_tree_baton_t,
db_op_copy_tree, svn_wc__db_op_copy_tree): New functions.
* subversion/libsvn_wc/wc-queries.sql
(STMT_COPY_NODES_ROW, STMT_COPY_NODES_AT_SAME_OP_DEPTH,
STMT_COPY_NODES_AT_GREATER_OP_DEPTH, STMT_COPY_ACTUAL_NODE_ROWS):
New statements.
* subversion/tests/libsvn_wc/op-depth-test.c
(compare_nodes_rows): Ignore mismatches that are due to copy-from info
that should have been elided (because it matches its parent) but wasn't.
(test_funcs): Expect test 1 to PASS.
Modified:
subversion/trunk/subversion/libsvn_wc/copy.c
subversion/trunk/subversion/libsvn_wc/wc-queries.sql
subversion/trunk/subversion/libsvn_wc/wc_db.c
subversion/trunk/subversion/libsvn_wc/wc_db.h
Modified: subversion/trunk/subversion/libsvn_wc/copy.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/copy.c?rev=1027851&r1=1027850&r2=1027851&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/copy.c (original)
+++ subversion/trunk/subversion/libsvn_wc/copy.c Wed Oct 27 08:12:58 2010
@@ -120,6 +120,7 @@ copy_to_tmpdir(const char **dst_abspath,
}
+#ifndef SVN_WC__OP_DEPTH
/* If SRC_ABSPATH and DST_ABSPATH use different pristine stores, copy the
pristine text of SRC_ABSPATH (if there is one) into the pristine text
store connected to DST_ABSPATH. This will only happen when copying into
@@ -431,6 +432,7 @@ copy_versioned_dir(svn_wc__db_t *db,
return SVN_NO_ERROR;
}
+#endif
#ifdef SVN_WC__OP_DEPTH
@@ -442,10 +444,14 @@ from one valid state to another and must
Several such changes can be batched together in a bigger txn if we don't
want clients to be able to see intermediate states.
-### TODO: This plan doesn't yet provide well for notification of all copied
- paths.
+TODO: We will probably want to notify all copied paths rather than just the
+ root path, some time in the future. It may be difficult to get the list
+ of visited paths directly, because the metadata copying is performed
+ within a single SQL statement. We could walk the destination tree after
+ copying, taking care to include any 'excluded' nodes but ignore any
+ 'deleted' paths that may be left over from a replaced sub-tree.
-copy-versioned_node:
+copy_versioned_node:
# Copy a versioned file/dir SRC_PATH to DST_PATH, recursively.
# This function takes care to copy both the metadata tree and the disk
@@ -475,6 +481,68 @@ copy-versioned_node:
# and so subsume the destination into an existing op? I guess not.
*/
+
+/* Copy a versioned file/dir SRC_PATH to DST_PATH, recursively. */
+static svn_error_t *
+copy_versioned_node(svn_wc__db_t *db,
+ const char *src_abspath,
+ const char *dst_abspath,
+ svn_boolean_t metadata_only,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_skel_t *work_item = NULL;
+
+ /* Prepare a copy of the on-disk tree (if it exists, and whatever its kind),
+ * in a temporary location. */
+ if (! metadata_only)
+ {
+ const char *tmpdir_abspath;
+ const char *tmp_dst_abspath;
+ svn_node_kind_t kind;
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db, dst_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath,
+ tmpdir_abspath,
+ TRUE, /* recursive */
+ cancel_func, cancel_baton,
+ scratch_pool));
+ if (tmp_dst_abspath)
+ {
+ SVN_ERR(svn_wc__wq_build_file_move(&work_item, db,
+ tmp_dst_abspath, dst_abspath,
+ scratch_pool, scratch_pool));
+ }
+ }
+
+ /* Copy single NODES row from src_p...@src_op_depth to dst_p...@dst_depth. */
+ /* Copy all rows of descendent paths in == src_op_depth to == dst_depth. */
+ /* Copy all rows of descendent paths in > src_depth to > dst_depth,
+ adjusting op_depth by (dst_depth - src_depth). */
+ /* Copy ACTUAL_NODE rows (props and any other actual metadata). */
+ SVN_ERR(svn_wc__db_op_copy_tree(db, src_abspath, dst_abspath,
+ work_item, scratch_pool));
+
+ SVN_ERR(svn_wc__wq_run(db, dst_abspath, cancel_func, cancel_baton,
+ scratch_pool));
+
+ /* Notify */
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify
+ = svn_wc_create_notify(dst_abspath, svn_wc_notify_add,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ (*notify_func)(notify_baton, notify, scratch_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
#endif
@@ -645,6 +713,13 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
scratch_pool));
}
+#ifdef SVN_WC__OP_DEPTH
+ SVN_ERR(copy_versioned_node(db, src_abspath, dst_abspath,
+ metadata_only,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
+#else
if (src_db_kind == svn_wc__db_kind_file
|| src_db_kind == svn_wc__db_kind_symlink)
{
@@ -660,6 +735,7 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
notify_func, notify_baton,
scratch_pool));
}
+#endif
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1027851&r1=1027850&r2=1027851&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed Oct 27 08:12:58
2010
@@ -533,6 +533,74 @@ SELECT 1 FROM nodes WHERE wc_id = ?1 AND
WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > 0);
+-- STMT_COPY_NODES_ROW
+INSERT OR REPLACE INTO nodes (
+ wc_id, local_relpath, op_depth, parent_relpath,
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */ )
+SELECT wc_id,
+ ?4 /*dst_relpath*/,
+ ?6 /*dst_op_depth*/,
+ ?5 /*dst_parent_*/,
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */
+FROM nodes
+WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3;
+
+-- STMT_COPY_NODES_AT_SAME_OP_DEPTH
+INSERT OR REPLACE INTO nodes (
+ wc_id, local_relpath, op_depth, parent_relpath,
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */ )
+SELECT wc_id,
+ ?4 /*dst_relpath*/ || SUBSTR(local_relpath, ?6 /*LEN(src_relpath)+1*/),
+ ?5 /*dst_depth*/,
+ ?4 /*dst_relpath*/ || SUBSTR(parent_relpath, ?6 /*LEN(src_relpath)+1*/),
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */
+FROM nodes
+WHERE wc_id = ?1 AND local_relpath LIKE ?2 ESCAPE '#' AND op_depth = ?3;
+
+-- STMT_COPY_NODES_AT_GREATER_OP_DEPTH
+INSERT OR REPLACE INTO nodes (
+ wc_id, local_relpath, op_depth, parent_relpath,
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */ )
+SELECT wc_id,
+ ?4 /*dst_relpath*/ || SUBSTR(local_relpath, ?6 /*LEN(src_relpath)+1*/),
+ op_depth + ?5 /*dst_depth*/ - ?3 /*src_depth*/,
+ ?4 /*dst_relpath*/ || SUBSTR(parent_relpath, ?6 /*LEN(src_relpath)+1*/),
+ repos_id, repos_path, revision, presence, /* moved_here, moved_to, */
+ kind, properties, depth, checksum, symlink_target,
+ changed_revision, changed_date, changed_author,
+ translated_size, last_mod_time /* dav_cache, file_external */
+FROM nodes
+WHERE wc_id = ?1 AND local_relpath LIKE ?2 ESCAPE '#' AND op_depth > ?3;
+
+-- STMT_COPY_ACTUAL_NODE_ROWS
+INSERT OR REPLACE INTO actual_node (
+ wc_id, local_relpath, parent_relpath, properties,
+ conflict_old, conflict_new, conflict_working,
+ prop_reject, changelist, text_mod, tree_conflict_data )
+SELECT wc_id,
+ ?4 /*dst_relpath*/ || SUBSTR(local_relpath, ?6 /*LEN(src_relpath)+1*/),
+ ?5 /*dst_parent_*/ || SUBSTR(parent_relpath, ?7 /*LEN(src_parent_)+1*/),
+ properties,
+ conflict_old, conflict_new, conflict_working,
+ prop_reject, changelist, text_mod, tree_conflict_data
+FROM actual_node
+WHERE wc_id = ?1 AND (local_relpath = ?2 OR local_relpath LIKE ?3 ESCAPE '#');
+
/* ### Why can't this query not just use the BASE repository
location values, instead of taking 3 additional parameters?! */
-- STMT_INSERT_WORKING_NODE_COPY_FROM_BASE
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1027851&r1=1027850&r2=1027851&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed Oct 27 08:12:58 2010
@@ -3089,6 +3089,189 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
return SVN_NO_ERROR;
}
+/* Set *OP_DEPTH to the highest op depth of PDH:LOCAL_RELPATH. */
+static svn_error_t *
+op_depth_of(apr_int64_t *op_depth,
+ svn_wc__db_pdh_t *pdh,
+ const char *local_relpath)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_NODE_INFO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR_ASSERT(have_row);
+ *op_depth = svn_sqlite__column_int64(stmt, 0);
+ SVN_ERR(svn_sqlite__reset(stmt));
+ return SVN_NO_ERROR;
+}
+
+/*
+ * Copy single NODES row from src_p...@src_op_depth to dst_p...@dst_depth.
+ * Copy all rows of descendent paths in == src_op_depth to == dst_depth.
+ * Copy all rows of descendent paths in > src_depth to > dst_depth,
+ * adjusting op_depth by (dst_depth - src_depth).
+ *
+ * ### TODO: Return a list of copied nodes. */
+static svn_error_t *
+copy_nodes_rows(svn_wc__db_pdh_t *src_pdh,
+ const char *src_relpath,
+ svn_wc__db_pdh_t *dst_pdh,
+ const char *dst_relpath,
+ apr_pool_t *scratch_pool)
+{
+ apr_int64_t src_op_depth;
+ apr_int64_t src_depth = relpath_depth(src_relpath);
+ apr_int64_t dst_depth = relpath_depth(dst_relpath);
+ svn_sqlite__stmt_t *stmt;
+ const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath,
+ scratch_pool);
+
+ SVN_ERR(op_depth_of(&src_op_depth, src_pdh, src_relpath));
+
+ /* Root node */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
+ STMT_COPY_NODES_ROW));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isissi",
+ src_pdh->wcroot->wc_id,
+ src_relpath,
+ src_op_depth,
+ dst_relpath,
+ dst_parent_relpath,
+ dst_depth));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* Descendants at same depth */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
+ STMT_COPY_NODES_AT_SAME_OP_DEPTH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isisii",
+ src_pdh->wcroot->wc_id,
+ construct_like_arg(src_relpath, scratch_pool),
+ src_op_depth,
+ dst_relpath,
+ dst_depth,
+ (apr_int64_t)(strlen(src_relpath) + 1)));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* Descendants at greater depths */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
+ STMT_COPY_NODES_AT_GREATER_OP_DEPTH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isisii",
+ src_pdh->wcroot->wc_id,
+ construct_like_arg(src_relpath, scratch_pool),
+ src_depth,
+ dst_relpath,
+ dst_depth,
+ (apr_int64_t)(strlen(src_relpath) + 1)));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+copy_actual_rows(svn_wc__db_pdh_t *src_pdh,
+ const char *src_relpath,
+ svn_wc__db_pdh_t *dst_pdh,
+ const char *dst_relpath,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ const char *src_parent_relpath = svn_relpath_dirname(src_relpath,
+ scratch_pool);
+ const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath,
+ scratch_pool);
+
+ /* ### Copying changelist is OK for a move but what about a copy? */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, dst_pdh->wcroot->sdb,
+ STMT_COPY_ACTUAL_NODE_ROWS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "issssii",
+ src_pdh->wcroot->wc_id, src_relpath,
+ construct_like_arg(src_relpath, scratch_pool),
+ dst_relpath, dst_parent_relpath,
+ strlen(src_relpath) + 1,
+ strlen(src_parent_relpath) + 1));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ return SVN_NO_ERROR;
+}
+
+
+struct copy_tree_baton_t
+{
+ svn_wc__db_pdh_t *src_pdh, *dst_pdh;
+ const char *src_relpath, *dst_relpath;
+ const svn_skel_t *work_items;
+};
+
+/* */
+static svn_error_t *
+db_op_copy_tree(void *baton,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
+{
+ struct copy_tree_baton_t *b = baton;
+
+ SVN_ERR(copy_nodes_rows(b->src_pdh, b->src_relpath,
+ b->dst_pdh, b->dst_relpath,
+ scratch_pool));
+
+ SVN_ERR(copy_actual_rows(b->src_pdh, b->src_relpath,
+ b->dst_pdh, b->dst_relpath,
+ scratch_pool));
+
+ SVN_ERR(add_work_items(b->dst_pdh->wcroot->sdb, b->work_items,
scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_op_copy_tree(svn_wc__db_t *db,
+ const char *src_abspath,
+ const char *dst_abspath,
+ const svn_skel_t *work_items,
+ apr_pool_t *scratch_pool)
+{
+ struct copy_tree_baton_t b;
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&b.src_pdh, &b.src_relpath, db,
+ src_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(b.src_pdh);
+
+ SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&b.dst_pdh, &b.dst_relpath, db,
+ dst_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(b.dst_pdh);
+
+ b.work_items = work_items;
+
+ if (b.src_pdh->wcroot == b.dst_pdh->wcroot)
+ {
+ /* ASSERT(presence == normal) */
+
+ SVN_ERR(svn_sqlite__with_transaction(b.dst_pdh->wcroot->sdb,
+ db_op_copy_tree, &b, scratch_pool));
+
+ /* ### Do we need to flush entries?
+ * SVN_ERR(flush_entries(db, b.dst_pdh, dst_abspath, scratch_pool)); */
+ }
+ else
+ {
+ /* Cross-DB copy */
+ SVN_ERR(db_op_copy(b.src_pdh, b.src_relpath, b.dst_pdh, b.dst_relpath,
+ b.work_items, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_wc__db_op_copy_dir(svn_wc__db_t *db,
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1027851&r1=1027850&r2=1027851&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Wed Oct 27 08:12:58 2010
@@ -1010,6 +1010,18 @@ svn_wc__db_pristine_repair(svn_wc__db_t
@{
*/
+/* Copy the tree at SRC_ABSPATH (in NODES and ACTUAL_NODE tables) to
+ * DST_ABSPATH, both in DB. The parent of DST_ABSPATH must be a versioned
+ * directory.
+ *
+ * Add WORK_ITEMS to the work queue. */
+svn_error_t *
+svn_wc__db_op_copy_tree(svn_wc__db_t *db,
+ const char *src_abspath,
+ const char *dst_abspath,
+ const svn_skel_t *work_items,
+ apr_pool_t *scratch_pool);
+
/* Copy the node at SRC_ABSPATH (in NODES and ACTUAL_NODE tables) to
* DST_ABSPATH, both in DB but not necessarily in the same WC. The parent
* of DST_ABSPATH must be a versioned directory.