You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2012/06/01 21:27:14 UTC

svn commit: r1345317 - /subversion/trunk/subversion/libsvn_wc/copy.c

Author: rhuijben
Date: Fri Jun  1 19:27:13 2012
New Revision: 1345317

URL: http://svn.apache.org/viewvc?rev=1345317&view=rev
Log:
Retrieving information on what to copy during 'svn cp PATH1 PATH2' per
directory instead of per node to greatly reduce the number of sqlite
transactions.

For copies within a single working copy this reduces the number of
transactions with about three per file, two per file if we are copying
between working copies.

For a 'svn cp 1.7.x 1.7.x-copied' from a sparse ^/subversion/branches checkout
this about halves the time needed to copy (70 sec -> 33 sec) while profiling
for me.

* subversion/libsvn_wc/copy.c
  (copy_versioned_file): Replace the checksum argument with a
    copy_pristine_file boolean that just tells if copying is necessary.
    Retrieve checksum if necessary.
  (copy_versioned_dir): Add within_one_wc argument. Don't run the wc if we
    didn't install items. Read the info for the children instead of just the
    names to avoid a read_info for every node and read_base for most files.
    Use within_one_dir to tell copy_versioned_file if a pristine file must be
    copied. Update recursive call.
  (copy_or_move): Determine if we are copying within a single working copy and
    pass that information.

Modified:
    subversion/trunk/subversion/libsvn_wc/copy.c

Modified: subversion/trunk/subversion/libsvn_wc/copy.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/copy.c?rev=1345317&r1=1345316&r2=1345317&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/copy.c (original)
+++ subversion/trunk/subversion/libsvn_wc/copy.c Fri Jun  1 19:27:13 2012
@@ -178,6 +178,9 @@ copy_pristine_text_if_necessary(svn_wc__
    If IS_MOVE is true, record move information in working copy meta
    data in addition to copying the file.
 
+   If COPY_PRISTINE_FILE is true, make sure the necessary pristine files are
+   available in the destination working copy.
+
    If the versioned file has a text conflict, and the .mine file exists in
    the filesystem, copy the .mine file to DST_ABSPATH.  Otherwise, copy the
    versioned file itself.
@@ -190,7 +193,7 @@ copy_versioned_file(svn_wc__db_t *db,
                     const char *dst_abspath,
                     const char *dst_op_root_abspath,
                     const char *tmpdir_abspath,
-                    const svn_checksum_t *checksum,
+                    svn_boolean_t copy_pristine_file,
                     svn_boolean_t metadata_only,
                     svn_boolean_t conflicted,
                     svn_boolean_t is_move,
@@ -206,12 +209,24 @@ copy_versioned_file(svn_wc__db_t *db,
   /* In case we are copying from one WC to another (e.g. an external dir),
      ensure the destination WC has a copy of the pristine text. */
 
-  /* Checksum is NULL for local additions */
-  if (checksum != NULL)
-    SVN_ERR(copy_pristine_text_if_necessary(db, src_abspath, dst_abspath,
-                                            tmpdir_abspath, checksum,
-                                            cancel_func, cancel_baton,
-                                            scratch_pool));
+  if (copy_pristine_file)
+    {
+      const svn_checksum_t *checksum;
+      SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, &checksum, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                   db, src_abspath,
+                                   scratch_pool, scratch_pool));
+
+      /* Checksum is NULL for local additions, but that should be handled
+         by our caller*/
+      if (checksum != NULL)
+        SVN_ERR(copy_pristine_text_if_necessary(db, src_abspath, dst_abspath,
+                                                tmpdir_abspath, checksum,
+                                                cancel_func, cancel_baton,
+                                                scratch_pool));
+    }
 
   /* Prepare a temp copy of the filesystem node.  It is usually a file, but
      copy recursively if it's a dir. */
@@ -334,7 +349,10 @@ copy_versioned_file(svn_wc__db_t *db,
    otherwise copy both the versioned metadata and the filesystem nodes (even
    if they are the wrong kind, and including unversioned children).
    If IS_MOVE is true, record move information in working copy meta
-   data in addition to copying the directory. */
+   data in addition to copying the directory.
+
+   WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root)
+ */
 static svn_error_t *
 copy_versioned_dir(svn_wc__db_t *db,
                    const char *src_abspath,
@@ -343,6 +361,7 @@ copy_versioned_dir(svn_wc__db_t *db,
                    const char *tmpdir_abspath,
                    svn_boolean_t metadata_only,
                    svn_boolean_t is_move,
+                   svn_boolean_t within_one_wc,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    svn_wc_notify_func2_t notify_func,
@@ -351,11 +370,12 @@ copy_versioned_dir(svn_wc__db_t *db,
 {
   svn_skel_t *work_items = NULL;
   const char *dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
-  const apr_array_header_t *versioned_children;
+  apr_hash_t *versioned_children;
+  apr_hash_t *conflicted_children;
   apr_hash_t *disk_children;
+  apr_hash_index_t *hi;
   svn_node_kind_t disk_kind;
   apr_pool_t *iterpool;
-  int i;
 
   /* Prepare a temp copy of the single filesystem node (usually a dir). */
   if (!metadata_only)
@@ -381,8 +401,9 @@ copy_versioned_dir(svn_wc__db_t *db,
   SVN_ERR(svn_wc__db_op_copy(db, src_abspath, dst_abspath,
                              dst_op_root_abspath, is_move, work_items,
                              scratch_pool));
-  SVN_ERR(svn_wc__wq_run(db, dir_abspath,
-                         cancel_func, cancel_baton, scratch_pool));
+  if (work_items != NULL)
+    SVN_ERR(svn_wc__wq_run(db, dir_abspath,
+                           cancel_func, cancel_baton, scratch_pool));
 
   if (notify_func)
     {
@@ -403,79 +424,61 @@ copy_versioned_dir(svn_wc__db_t *db,
     disk_children = NULL;
 
   /* Copy all the versioned children */
-  SVN_ERR(svn_wc__db_read_children(&versioned_children, db, src_abspath,
-                                   scratch_pool, scratch_pool));
   iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < versioned_children->nelts; ++i)
+  SVN_ERR(svn_wc__db_read_children_info(&versioned_children,
+                                        &conflicted_children,
+                                        db, src_abspath,
+                                        scratch_pool, iterpool));
+  for (hi = apr_hash_first(scratch_pool, versioned_children);
+       hi;
+       hi = apr_hash_next(hi))
     {
       const char *child_name, *child_src_abspath, *child_dst_abspath;
-      svn_wc__db_status_t child_status;
-      svn_kind_t child_kind;
-      svn_boolean_t op_root;
-      svn_boolean_t conflicted;
-      const svn_checksum_t *checksum;
+      struct svn_wc__db_info_t *info;
 
       svn_pool_clear(iterpool);
+
       if (cancel_func)
         SVN_ERR(cancel_func(cancel_baton));
 
-      child_name = APR_ARRAY_IDX(versioned_children, i, const char *);
+      child_name = svn__apr_hash_index_key(hi);
+      info = svn__apr_hash_index_val(hi);
       child_src_abspath = svn_dirent_join(src_abspath, child_name, iterpool);
       child_dst_abspath = svn_dirent_join(dst_abspath, child_name, iterpool);
 
-      SVN_ERR(svn_wc__db_read_info(&child_status, &child_kind, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL, NULL,
-                                   &checksum, NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, &conflicted,
-                                   &op_root, NULL, NULL, NULL, NULL, NULL,
-                                   db, child_src_abspath,
-                                   iterpool, iterpool));
-
-      if (op_root)
+      if (info->op_root)
         SVN_ERR(svn_wc__db_op_copy_shadowed_layer(db,
                                                   child_src_abspath,
                                                   child_dst_abspath,
                                                   is_move,
                                                   scratch_pool));
 
-      if (child_status == svn_wc__db_status_normal
-          || child_status == svn_wc__db_status_added)
+      if (info->status == svn_wc__db_status_normal
+          || info->status == svn_wc__db_status_added)
         {
           /* We have more work to do than just changing the DB */
-          if (child_kind == svn_kind_file)
+          if (info->kind == svn_kind_file)
             {
-              svn_boolean_t skip = FALSE;
-
               /* We should skip this node if this child is a file external
                  (issues #3589, #4000) */
-              if (child_status == svn_wc__db_status_normal)
-                {
-                  SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
-                                                   NULL, NULL, NULL, NULL,
-                                                   NULL, NULL, NULL, NULL,
-                                                   NULL, NULL, &skip,
-                                                   db, child_src_abspath,
-                                                   scratch_pool,
-                                                   scratch_pool));
-                }
-
-              if (!skip)
+              if (!info->file_external)
                 SVN_ERR(copy_versioned_file(db,
                                             child_src_abspath,
                                             child_dst_abspath,
                                             dst_op_root_abspath,
-                                            tmpdir_abspath, checksum,
-                                            metadata_only, conflicted,
+                                            tmpdir_abspath,
+                                            !within_one_wc && info->has_checksum,
+                                            metadata_only, info->conflicted,
                                             is_move,
                                             cancel_func, cancel_baton,
                                             NULL, NULL,
                                             iterpool));
             }
-          else if (child_kind == svn_kind_dir)
+          else if (info->kind == svn_kind_dir)
             SVN_ERR(copy_versioned_dir(db,
                                        child_src_abspath, child_dst_abspath,
                                        dst_op_root_abspath, tmpdir_abspath,
-                                       metadata_only, is_move,
+                                       metadata_only, is_move, within_one_wc,
                                        cancel_func, cancel_baton, NULL, NULL,
                                        iterpool));
           else
@@ -484,9 +487,9 @@ copy_versioned_dir(svn_wc__db_t *db,
                                      svn_dirent_local_style(child_src_abspath,
                                                             scratch_pool));
         }
-      else if (child_status == svn_wc__db_status_deleted
-          || child_status == svn_wc__db_status_not_present
-          || child_status == svn_wc__db_status_excluded)
+      else if (info->status == svn_wc__db_status_deleted
+          || info->status == svn_wc__db_status_not_present
+          || info->status == svn_wc__db_status_excluded)
         {
           /* This will be copied as some kind of deletion. Don't touch
              any actual files */
@@ -497,7 +500,7 @@ copy_versioned_dir(svn_wc__db_t *db,
           /* Don't recurse on children while all we do is creating not-present
              children */
         }
-      else if (child_status == svn_wc__db_status_incomplete)
+      else if (info->status == svn_wc__db_status_incomplete)
         {
           /* Should go ahead and copy incomplete to incomplete? Try to
              copy as much as possible, or give up early? */
@@ -508,7 +511,7 @@ copy_versioned_dir(svn_wc__db_t *db,
         }
       else
         {
-          SVN_ERR_ASSERT(child_status == svn_wc__db_status_server_excluded);
+          SVN_ERR_ASSERT(info->status == svn_wc__db_status_server_excluded);
 
           return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                    _("Cannot copy '%s' excluded by server"),
@@ -517,8 +520,8 @@ copy_versioned_dir(svn_wc__db_t *db,
         }
 
       if (disk_children
-          && (child_status == svn_wc__db_status_normal
-              || child_status == svn_wc__db_status_added))
+          && (info->status == svn_wc__db_status_normal
+              || info->status == svn_wc__db_status_added))
         {
           /* Remove versioned child as it has been handled */
           apr_hash_set(disk_children, child_name, APR_HASH_KEY_STRING, NULL);
@@ -604,6 +607,9 @@ copy_or_move(svn_wc_context_t *wc_ctx,
   svn_boolean_t conflicted;
   const svn_checksum_t *checksum;
   const char *tmpdir_abspath;
+  const char *src_wcroot_abspath;
+  const char *dst_wcroot_abspath;
+  svn_boolean_t within_one_wc;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
   SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
@@ -637,6 +643,10 @@ copy_or_move(svn_wc_context_t *wc_ctx,
     else
       SVN_ERR(err);
 
+    /* Do this now, as we know the right data is cached */
+    SVN_ERR(svn_wc__db_get_wcroot(&src_wcroot_abspath, db, src_abspath,
+                                  scratch_pool, scratch_pool));
+
     switch (src_status)
       {
         case svn_wc__db_status_deleted:
@@ -665,6 +675,10 @@ copy_or_move(svn_wc_context_t *wc_ctx,
                                  db, dstdir_abspath,
                                  scratch_pool, scratch_pool));
 
+    /* Do this now, as we know the right data is cached */
+    SVN_ERR(svn_wc__db_get_wcroot(&dst_wcroot_abspath, db, dstdir_abspath,
+                                  scratch_pool, scratch_pool));
+
     if (!src_repos_root_url)
       {
         if (src_status == svn_wc__db_status_added)
@@ -777,14 +791,17 @@ copy_or_move(svn_wc_context_t *wc_ctx,
     }
 
   SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db,
-                                         dst_abspath,
+                                         dstdir_abspath,
                                          scratch_pool, scratch_pool));
 
+  within_one_wc = (strcmp(src_wcroot_abspath, dst_wcroot_abspath) == 0);
+
   if (src_db_kind == svn_kind_file
       || src_db_kind == svn_kind_symlink)
     {
       SVN_ERR(copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath,
-                                  tmpdir_abspath, checksum,
+                                  tmpdir_abspath,
+                                  !within_one_wc && (checksum != NULL),
                                   metadata_only, conflicted, is_move,
                                   cancel_func, cancel_baton,
                                   notify_func, notify_baton,
@@ -794,7 +811,7 @@ copy_or_move(svn_wc_context_t *wc_ctx,
     {
       SVN_ERR(copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath,
                                  tmpdir_abspath,
-                                 metadata_only, is_move,
+                                 metadata_only, is_move, within_one_wc,
                                  cancel_func, cancel_baton,
                                  notify_func, notify_baton,
                                  scratch_pool));