Author: rhuijben
Date: Mon May  9 20:57:05 2011
New Revision: 1101220

URL: http://svn.apache.org/viewvc?rev=1101220&view=rev
Log:
Optimize the status walker a bit for the specific case where it is used on an
single target inside a huge directory. Fix two pool lifetime issues and a small
lock retrieve problem identified by running the test suite with the original
version of this patch.

This specific case is used when you do 'svn rm file' and this severly impacts
the delete performance when you have a directory with about 16k files.

* subversion/libsvn_wc/status.c
  (read_info): Allocate result in the right pool. Fetch the lock from BASE if
    necessary.
  (get_repos_root_url_relpath): Allocate result in the result pool.

  (get_dir_status): Use subpool for function wide allocations, iterpool for
    temp work. Avoid the svn_wc__db_read_children_info when we only need a
    single node in this directory. Simplify another depth check.

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

Modified: subversion/trunk/subversion/libsvn_wc/status.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1101220&r1=1101219&r2=1101220&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/status.c (original)
+++ subversion/trunk/subversion/libsvn_wc/status.c Mon May  9 20:57:05 2011
@@ -247,7 +247,7 @@ read_info(const struct svn_wc__db_info_t
           apr_pool_t *result_pool,
           apr_pool_t *scratch_pool)
 {
-  struct svn_wc__db_info_t *mtb = apr_pcalloc(scratch_pool, sizeof(*mtb));
+  struct svn_wc__db_info_t *mtb = apr_pcalloc(result_pool, sizeof(*mtb));
 
   SVN_ERR(svn_wc__db_read_info(&mtb->status, &mtb->kind,
                                &mtb->revnum, &mtb->repos_relpath,
@@ -262,6 +262,19 @@ read_info(const struct svn_wc__db_info_t
                                db, local_abspath,
                                result_pool, scratch_pool));
 
+  /* Maybe we have to get some shadowed lock from BASE to make our test suite
+     happy... (It might be completely unrelated, but...) */
+  if (mtb->have_base
+      && (mtb->status == svn_wc__db_status_added
+         || mtb->status == svn_wc__db_status_deleted))
+    {
+      SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL,
+                                       &mtb->lock, NULL, NULL, NULL,
+                                       db, local_abspath,
+                                       result_pool, scratch_pool));
+    }
+
 #ifdef HAVE_SYMLINK
   if (mtb->had_props || mtb->props_mod)
     {
@@ -308,7 +321,7 @@ get_repos_root_url_relpath(const char **
       *repos_relpath = svn_relpath_join(parent_repos_relpath,
                                         svn_dirent_basename(local_abspath,
                                                             NULL),
-                                        scratch_pool);
+                                        result_pool);
       *repos_root_url = parent_repos_root_url;
     }
   else if (info->status == svn_wc__db_status_added)
@@ -1044,12 +1057,7 @@ get_dir_status(const struct walk_status_
 
   iterpool = svn_pool_create(subpool);
 
-  /* ### Performance: Use read_info() on single path if selected != NULL */
-  SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
-                                        wb->db, local_abspath,
-                                        subpool, iterpool));
-
-  err = svn_io_get_dirents3(&dirents, local_abspath, FALSE, subpool, subpool);
+  err = svn_io_get_dirents3(&dirents, local_abspath, FALSE, subpool, iterpool);
   if (err
       && (APR_STATUS_IS_ENOENT(err->apr_err)
          || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
@@ -1062,26 +1070,60 @@ get_dir_status(const struct walk_status_
 
   if (!dir_info)
     SVN_ERR(read_info(&dir_info, local_abspath, wb->db,
-                      scratch_pool, scratch_pool));
+                      subpool, iterpool));
 
   SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
                                      dir_info, parent_repos_relpath,
                                      parent_repos_root_url,
                                      wb->db, local_abspath,
-                                     scratch_pool, scratch_pool));
+                                     subpool, iterpool));
   if (selected == NULL)
     {
       /* Create a hash containing all children.  The source hashes
          don't all map the same types, but only the keys of the result
          hash are subsequently used. */
+      SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
+                                        wb->db, local_abspath,
+                                        subpool, iterpool));
+
       all_children = apr_hash_overlay(subpool, nodes, dirents);
       if (apr_hash_count(conflicts) > 0)
         all_children = apr_hash_overlay(subpool, conflicts, all_children);
     }
   else
     {
+      const struct svn_wc__db_info_t *info;
+      const char *selected_abspath = svn_dirent_join(local_abspath, selected,
+                                                     iterpool);
       /* Create a hash containing just selected */
       all_children = apr_hash_make(subpool);
+      nodes = apr_hash_make(subpool);
+      conflicts = apr_hash_make(subpool);
+
+      err = read_info(&info, selected_abspath, wb->db, subpool, iterpool);
+
+      if (err)
+        {
+          if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+            return svn_error_return(err);
+          svn_error_clear(err);
+          /* The node is neither a tree conflict nor a versioned node */
+        }
+      else
+        {
+          if (!info->conflicted
+              || info->status != svn_wc__db_status_normal
+              || info->kind != svn_wc__db_kind_unknown)
+             {
+               /* The node is a normal versioned node */
+               apr_hash_set(nodes, selected, APR_HASH_KEY_STRING, info);
+             }
+
+          /* Drop it in the list of possible conflicts */
+          if (info->conflicted)
+            apr_hash_set(conflicts, selected, APR_HASH_KEY_STRING, info);
+        }
+
       apr_hash_set(all_children, selected, APR_HASH_KEY_STRING, selected);
     }
 
@@ -1147,11 +1189,9 @@ get_dir_status(const struct walk_status_
                                             status_func, status_baton,
                                             iterpool));
 
-              if (depth == svn_depth_immediates)
-                continue;
-
               /* Descend in subdirectories. */
-              if (info->kind == svn_wc__db_kind_dir)
+              if (depth == svn_depth_infinity
+                  && info->kind == svn_wc__db_kind_dir)
                 {
                   SVN_ERR(get_dir_status(wb, node_abspath, NULL, TRUE,
                                          dir_repos_root_url, dir_repos_relpath,


Reply via email to