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.


Reply via email to