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 2013/03/07 16:46:08 UTC

svn commit: r1453925 - in /subversion/trunk/subversion/libsvn_wc: props.c status.c wc_db.c wc_db.h

Author: rhuijben
Date: Thu Mar  7 15:46:08 2013
New Revision: 1453925

URL: http://svn.apache.org/r1453925
Log:
Handle 'svn:ignore' and 'svn:global-ignores' values as a single list for
status processing and for svn_wc_get_ignores2().

This patch simplifies some status code and makes a very expensive check per
directory that contains unversioned files cheaper.

On my profile working copy with unversioned files in every directory, but
no local changes this accounts for a +- 6% performance improvement on
'svn status'
(The amount of CPU time spend on obtaining these properties was reduced by 50%)

* subversion/libsvn_wc/props.c
  (svn_wc__get_iprops): Update caller.

* subversion/libsvn_wc/status.c
  (collect_ignore_patterns): Obtain a single list of patterns. Remove had_props
    optimization as that doesn't help for inherited properties anyway.
  (send_unversioned_item,
   one_child_status,
   get_dir_status): Remove inherited specialized code.

  (svn_wc_get_ignores2): Update code to really obtain all ignore patterns, as
    documented.

* subversion/libsvn_wc/wc_db.c
  (db_read_inherited_props): Add actual_props argument. Constify output array.
    Use db query directly to calculate whether the parent is what it should be
    and inherited property eligability with a single query. Obtain actual props
    if requested.
    Note that we are not really interested in switched paths here, but just if
    the parent directory is the parent of the child we are obtaining information
    for.

  (svn_wc__db_read_inherited_props): Obtain actual_props if requested.

* subversion/libsvn_wc/wc_db.h
  (svn_wc__db_read_inherited_props): Update documentation and prototype.

Modified:
    subversion/trunk/subversion/libsvn_wc/props.c
    subversion/trunk/subversion/libsvn_wc/status.c
    subversion/trunk/subversion/libsvn_wc/wc_db.c
    subversion/trunk/subversion/libsvn_wc/wc_db.h

Modified: subversion/trunk/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.c?rev=1453925&r1=1453924&r2=1453925&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/props.c (original)
+++ subversion/trunk/subversion/libsvn_wc/props.c Thu Mar  7 15:46:08 2013
@@ -2314,7 +2314,7 @@ svn_wc__get_iprops(apr_array_header_t **
                    apr_pool_t *scratch_pool)
 {
   return svn_error_trace(
-            svn_wc__db_read_inherited_props(inherited_props,
+            svn_wc__db_read_inherited_props(inherited_props, NULL,
                                             wc_ctx->db, local_abspath,
                                             propname,
                                             result_pool, scratch_pool));

Modified: subversion/trunk/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1453925&r1=1453924&r2=1453925&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/status.c (original)
+++ subversion/trunk/subversion/libsvn_wc/status.c Thu Mar  7 15:46:08 2013
@@ -962,17 +962,16 @@ send_status_structure(const struct walk_
 */
 static svn_error_t *
 collect_ignore_patterns(apr_array_header_t **patterns,
-                        apr_array_header_t **inherited_patterns,
                         svn_wc__db_t *db,
                         const char *local_abspath,
                         const apr_array_header_t *ignores,
-                        svn_boolean_t may_have_props,
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
   int i;
-  const svn_string_t *value;
-  apr_hash_t *props = NULL;
+  apr_hash_t *props;
+  const apr_array_header_t *inherited_props;
+  svn_error_t *err;
 
   /* ### assert we are passed a directory? */
 
@@ -986,56 +985,46 @@ collect_ignore_patterns(apr_array_header
                                                             ignore);
     }
 
-  if (may_have_props)
+  err = svn_wc__db_read_inherited_props(&inherited_props, &props,
+                                        db, local_abspath,
+                                        SVN_PROP_INHERITABLE_IGNORES,
+                                        scratch_pool, scratch_pool);
+
+  if (err)
     {
-      /* Add any svn:ignore globs to the PATTERNS array. */
-      SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
-                                    scratch_pool, scratch_pool));
+      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+        return svn_error_trace(err);
 
-      if (!props)
-        return SVN_NO_ERROR;
+      svn_error_clear(err);
+      return SVN_NO_ERROR;
+    }
+
+  if (props)
+    {
+      const svn_string_t *value;
 
-      value = apr_hash_get(props, SVN_PROP_IGNORE, APR_HASH_KEY_STRING);
+      value = svn_hash_gets(props, SVN_PROP_IGNORE);
+      if (value)
+        svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
+                                 result_pool);
 
-      if (value != NULL)
+      value = svn_hash_gets(props, SVN_PROP_INHERITABLE_IGNORES);
+      if (value)
         svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
                                  result_pool);
     }
 
-  if (inherited_patterns)
+  for (i = 0; i < inherited_props->nelts; i++)
     {
-      apr_array_header_t *inherited_props;
+      svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
+        inherited_props, i, svn_prop_inherited_item_t *);
+      const svn_string_t *value;
 
-      *inherited_patterns = apr_array_make(result_pool, 1,
-                                           sizeof(const char *));
-      if (props)
-        {
-          value = apr_hash_get(props, SVN_PROP_INHERITABLE_IGNORES,
-                               APR_HASH_KEY_STRING);
-          if (value != NULL)
-            svn_cstring_split_append(*inherited_patterns, value->data, "\n\r",
-                                     FALSE, result_pool);      
-        }
-
-      SVN_ERR(svn_wc__db_read_inherited_props(&inherited_props,
-                                              db, local_abspath,
-                                              SVN_PROP_INHERITABLE_IGNORES,
-                                              scratch_pool, scratch_pool));
-      for (i = 0; i < inherited_props->nelts; i++)
-        {
-          apr_hash_index_t *hi;
-          svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
-            inherited_props, i, svn_prop_inherited_item_t *);
-
-          for (hi = apr_hash_first(scratch_pool, elt->prop_hash);
-               hi;
-               hi = apr_hash_next(hi))
-            {
-              const svn_string_t *propval = svn__apr_hash_index_val(hi);
-              svn_cstring_split_append(*inherited_patterns, propval->data,
-                                       "\n\r", FALSE, result_pool);   
-            }
-        }
+      value = svn_hash_gets(elt->prop_hash, SVN_PROP_INHERITABLE_IGNORES);
+
+      if (value)
+        svn_cstring_split_append(*patterns, value->data,
+                                 "\n\r", FALSE, result_pool);
     }
 
   return SVN_NO_ERROR;
@@ -1097,26 +1086,21 @@ send_unversioned_item(const struct walk_
                       const svn_io_dirent2_t *dirent,
                       svn_boolean_t tree_conflicted,
                       const apr_array_header_t *patterns,
-                      const apr_array_header_t *inherited_patterns,
                       svn_boolean_t no_ignore,
                       svn_wc_status_func4_t status_func,
                       void *status_baton,
                       apr_pool_t *scratch_pool)
 {
   svn_boolean_t is_ignored;
-  svn_boolean_t is_mandatory_ignored;
   svn_boolean_t is_external;
   svn_wc_status3_t *status;
   const char *base_name = svn_dirent_basename(local_abspath, NULL);
 
   is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool);
-  is_mandatory_ignored = svn_wc_match_ignore_list(base_name,
-                                                  inherited_patterns,
-                                                  scratch_pool);
   SVN_ERR(assemble_unversioned(&status,
                                wb->db, local_abspath,
                                dirent, tree_conflicted,
-                               is_ignored || is_mandatory_ignored,
+                               is_ignored,
                                scratch_pool, scratch_pool));
 
   is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
@@ -1132,7 +1116,7 @@ send_unversioned_item(const struct walk_
   /* If we aren't ignoring it, or if it's an externals path, pass this
      entry to the status func. */
   if (no_ignore
-      || !(is_ignored || is_mandatory_ignored)
+      || !is_ignored
       || is_external)
     return svn_error_trace((*status_func)(status_baton, local_abspath,
                                           status, scratch_pool));
@@ -1181,20 +1165,18 @@ get_dir_status(const struct walk_status_
  *
  * DIR_HAS_PROPS is a boolean indicating whether PARENT_ABSPATH has properties.
  *
- * If *COLLECTED_IGNORE_PATTERNS or COLLECTED_INHERITED_IGNORE_PATTERNS are NULL
- * and ignore patterns are needed in this call, then *COLLECTED_IGNORE_PATTERNS
- * *COLLECTED_INHERITED_IGNORE_PATTERNS will be set to an apr_array_header_t*
+ * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in this
+ * call, then *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t*
  * containing all ignore patterns, as returned by collect_ignore_patterns() on
- * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS and 
- * COLLECTED_INHERITED_IGNORE_PATTERNS is passed non-NULL, it is assumed they
- * already hold those results. This speeds up repeated calls with the same
- * PARENT_ABSPATH.
+ * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed
+ *  non-NULL, it is assumed it already holds those results.
+ * This speeds up repeated calls with the same PARENT_ABSPATH.
  *
- * *COLLECTED_IGNORE_PATTERNS and COLLECTED_INHERITED_IGNORE_PATTERNS will be
- * allocated in RESULT_POOL. All other allocations are made in SCRATCH_POOL.
+ * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other
+ * allocations are made in SCRATCH_POOL.
  *
  * The remaining parameters correspond to get_dir_status(). */
-static svn_error_t*
+static svn_error_t *
 one_child_status(const struct walk_status_baton *wb,
                  const char *local_abspath,
                  const char *parent_abspath,
@@ -1203,10 +1185,8 @@ one_child_status(const struct walk_statu
                  const char *dir_repos_root_url,
                  const char *dir_repos_relpath,
                  const char *dir_repos_uuid,
-                 svn_boolean_t dir_has_props,
                  svn_boolean_t unversioned_tree_conflicted,
                  apr_array_header_t **collected_ignore_patterns,
-                 apr_array_header_t **collected_inherited_ignore_patterns,
                  const apr_array_header_t *ignore_patterns,
                  svn_depth_t depth,
                  svn_boolean_t get_all,
@@ -1289,13 +1269,9 @@ one_child_status(const struct walk_statu
    * determined.  For example, in 'svn status', plain unversioned nodes show
    * as '?  C', where ignored ones show as 'I  C'. */
 
-  if ((ignore_patterns && ! *collected_ignore_patterns)
-      || (collected_inherited_ignore_patterns
-          && ! collected_inherited_ignore_patterns))
+  if (ignore_patterns && ! *collected_ignore_patterns)
     SVN_ERR(collect_ignore_patterns(collected_ignore_patterns,
-                                    collected_inherited_ignore_patterns,
                                     wb->db, parent_abspath, ignore_patterns,
-                                    dir_has_props,
                                     result_pool, scratch_pool));
 
   SVN_ERR(send_unversioned_item(wb,
@@ -1303,7 +1279,6 @@ one_child_status(const struct walk_statu
                                 dirent,
                                 conflicted,
                                 *collected_ignore_patterns,
-                                *collected_inherited_ignore_patterns,
                                 no_ignore,
                                 status_func, status_baton,
                                 scratch_pool));
@@ -1357,7 +1332,6 @@ get_dir_status(const struct walk_status_
   apr_hash_t *dirents, *nodes, *conflicts, *all_children;
   apr_array_header_t *sorted_children;
   apr_array_header_t *collected_ignore_patterns = NULL;
-  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
   apr_pool_t *iterpool;
   svn_error_t *err;
   int i;
@@ -1486,10 +1460,8 @@ get_dir_status(const struct walk_status_
                                dir_repos_root_url,
                                dir_repos_relpath,
                                dir_repos_uuid,
-                               dir_has_props,
                                apr_hash_get(conflicts, key, klen) != NULL,
                                &collected_ignore_patterns,
-                               &collected_inherited_ignore_patterns,
                                ignore_patterns,
                                depth,
                                get_all,
@@ -1539,7 +1511,6 @@ get_child_status(const struct walk_statu
   const char *dir_repos_uuid;
   const struct svn_wc__db_info_t *dir_info;
   apr_array_header_t *collected_ignore_patterns = NULL;
-  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
   const char *parent_abspath = svn_dirent_dirname(local_abspath,
                                                   scratch_pool);
 
@@ -1571,10 +1542,8 @@ get_child_status(const struct walk_statu
                            dir_repos_root_url,
                            dir_repos_relpath,
                            dir_repos_uuid,
-                           (dir_info->had_props || dir_info->props_mod),
                            FALSE, /* unversioned_tree_conflicted */
                            &collected_ignore_patterns,
-                           &collected_inherited_ignore_patterns,
                            ignore_patterns,
                            svn_depth_empty,
                            get_all,
@@ -3092,8 +3061,8 @@ svn_wc_get_ignores2(apr_array_header_t *
   apr_array_header_t *default_ignores;
 
   SVN_ERR(svn_wc_get_default_ignores(&default_ignores, config, scratch_pool));
-  return svn_error_trace(collect_ignore_patterns(patterns, NULL, wc_ctx->db,
+  return svn_error_trace(collect_ignore_patterns(patterns, wc_ctx->db,
                                                  local_abspath,
-                                                 default_ignores, TRUE,
+                                                 default_ignores,
                                                  result_pool, scratch_pool));
 }

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1453925&r1=1453924&r2=1453925&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Mar  7 15:46:08 2013
@@ -9641,7 +9641,8 @@ filter_unwanted_props(apr_hash_t *prop_h
 /* The body of svn_wc__db_read_inherited_props().
  */
 static svn_error_t *
-db_read_inherited_props(apr_array_header_t **iprops,
+db_read_inherited_props(const apr_array_header_t **inherited_props,
+                        apr_hash_t **actual_props,
                         svn_wc__db_wcroot_t *wcroot,
                         const char *local_relpath,
                         const char *propname,
@@ -9650,54 +9651,112 @@ db_read_inherited_props(apr_array_header
 {
   int i;
   apr_array_header_t *cached_iprops = NULL;
-  const char *parent_relpath = local_relpath;
-  svn_boolean_t is_wc_root = FALSE;
+  apr_array_header_t *iprops;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  svn_sqlite__stmt_t *stmt;
+  apr_hash_t *props = NULL;
+  const char *relpath;
+  const char *expected_parent_repos_relpath = NULL;
+  const char *parent_relpath;
 
-  *iprops = apr_array_make(result_pool, 1,
+  iprops = apr_array_make(result_pool, 1,
                            sizeof(svn_prop_inherited_item_t *));
+  *inherited_props = iprops;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_NODE_INFO));
+
+  relpath = local_relpath;
 
   /* Walk up to the root of the WC looking for inherited properties.  When we
      reach the WC root also check for cached inherited properties. */
-  while (TRUE)
+  for (relpath = local_relpath; relpath; relpath = parent_relpath)
     {
       apr_hash_t *actual_props;
-      svn_boolean_t is_switched;
+      svn_boolean_t have_row;
+      int op_depth;
+      svn_wc__db_status_t status;
+
+      parent_relpath = relpath[0] ? svn_relpath_dirname(relpath, scratch_pool)
+                                  : NULL;
 
       svn_pool_clear(iterpool);
 
-      if (*parent_relpath == '\0')
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, relpath));
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      if (!have_row)
+        return svn_error_createf(
+                    SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
+                    _("The node '%s' was not found."),
+                    path_for_error_message(wcroot, relpath,
+                                           scratch_pool));
+
+      op_depth = svn_sqlite__column_int(stmt, 0);
+
+      status = svn_sqlite__column_token(stmt, 3, presence_map);
+
+      if (status != svn_wc__db_status_normal
+          && status != svn_wc__db_status_incomplete)
+        return svn_error_createf(
+                    SVN_ERR_WC_PATH_UNEXPECTED_STATUS, svn_sqlite__reset(stmt),
+                    _("The node '%s' has a status that has no properties."),
+                    path_for_error_message(wcroot, relpath,
+                                           scratch_pool));
+
+      if (op_depth > 0)
         {
-          is_switched = FALSE;
-          is_wc_root = TRUE;
+          /* WORKING node. Nothing to check */
         }
-      else
-        SVN_ERR(db_is_switched(&is_switched, NULL, wcroot, parent_relpath,
-                               scratch_pool));
+      else if (expected_parent_repos_relpath)
+        {
+          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
 
-      if (is_switched || is_wc_root)
+          if (strcmp(expected_parent_repos_relpath, repos_relpath) != 0)
+            {
+              /* The child of this node has a different parent than this node
+                 (It is "switched"), so we can stop here. Note that switched
+                 with the same parent is not interesting for us here. */
+              SVN_ERR(svn_sqlite__reset(stmt));
+              break;
+            }
+
+          expected_parent_repos_relpath =
+              svn_relpath_dirname(expected_parent_repos_relpath, scratch_pool);
+        }
+      else
         {
-          is_wc_root = TRUE;
+          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
 
-          /* If the WC root is also the root of the repository then by
-             definition there are no inheritable properties to be had,
-             but checking for that is just as expensive as fetching them
-             anyway. */
+          expected_parent_repos_relpath =
+              svn_relpath_dirname(repos_relpath, scratch_pool);
+        }
 
-          /* Grab the cached inherited properties for the WC root. */
-          SVN_ERR(db_read_cached_iprops(&cached_iprops,
-                                        wcroot, parent_relpath,
-                                        result_pool, iterpool));
+      if (op_depth == 0
+          && !svn_sqlite__column_is_null(stmt, 16))
+        {
+          /* The node contains a cache. No reason to look further */
+          SVN_ERR(svn_sqlite__column_iprops(&cached_iprops, stmt, 16,
+                                            result_pool, iterpool));
+
+          parent_relpath = NULL; /* Stop after this */
         }
 
-      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
-         LOCAL_ABSPATH can inherit properties from it. */
-      if (strcmp(local_relpath, parent_relpath) != 0)
+      if (relpath == local_relpath && actual_props)
+        SVN_ERR(svn_sqlite__column_properties(&props, stmt, 14,
+                                              result_pool, scratch_pool));
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+
+      /* If PARENT_ABSPATH is a parent of LOCAL_ABSPATH, then LOCAL_ABSPATH
+         can inherit properties from it. */
+      if (relpath != local_relpath)
         {
-          SVN_ERR(db_read_props(&actual_props, wcroot, parent_relpath,
+          SVN_ERR(db_read_props(&actual_props, wcroot, relpath,
                                 result_pool, iterpool));
 
-          if (actual_props)
+          if (actual_props && apr_hash_count(actual_props))
             {
               /* If we only want PROPNAME filter out any other properties. */
               if (propname)
@@ -9709,22 +9768,15 @@ db_read_inherited_props(apr_array_header
                     apr_pcalloc(result_pool,
                                 sizeof(svn_prop_inherited_item_t));
                   iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
-                                                           parent_relpath,
+                                                           relpath,
                                                            result_pool);
 
                   iprop_elt->prop_hash = actual_props;
                   /* Build the output array in depth-first order. */
-                  svn_sort__array_insert(&iprop_elt, *iprops, 0);
+                  svn_sort__array_insert(&iprop_elt, iprops, 0);
                 }
             }
         }
-
-      /* Inheritance only goes as far as the nearest WC root. */
-      if (is_wc_root)
-        break;
-
-      /* Keep looking for the WC root. */
-      parent_relpath = svn_relpath_dirname(parent_relpath, scratch_pool);
     }
 
   if (cached_iprops)
@@ -9745,16 +9797,34 @@ db_read_inherited_props(apr_array_header
 
           /* If we didn't filter everything then keep this iprop. */
           if (apr_hash_count(cached_iprop->prop_hash))
-            svn_sort__array_insert(&cached_iprop, *iprops, 0);
+            svn_sort__array_insert(&cached_iprop, iprops, 0);
         }
     }
 
+  if (actual_props)
+    {
+      svn_boolean_t have_row;
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_ACTUAL_PROPS));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      if (have_row && !svn_sqlite__column_is_null(stmt, 0))
+        SVN_ERR(svn_sqlite__column_properties(actual_props, stmt, 0,
+                                              result_pool, iterpool));
+      else
+        *actual_props = props; /* Cached when we read that record */
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
+svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
+                                apr_hash_t **actual_props,
                                 svn_wc__db_t *db,
                                 const char *local_abspath,
                                 const char *propname,
@@ -9771,7 +9841,7 @@ svn_wc__db_read_inherited_props(apr_arra
                                                 scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops,
+  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops, actual_props,
                                               wcroot, local_relpath, propname,
                                               result_pool, scratch_pool),
                       wcroot);

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1453925&r1=1453924&r2=1453925&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Thu Mar  7 15:46:08 2013
@@ -2120,11 +2120,15 @@ svn_wc__db_read_pristine_props(apr_hash_
  * paths relative to the repository root URL for cached inherited
  * properties and absolute working copy paths otherwise.
  *
+ * If ACTUAL_PROPS is not NULL, then set *ACTUAL_PROPS to the actual
+ * properties stored on LOCAL_ABSPATH.
+ *
  * Allocate @a *iprops in @a result_pool.  Use @a scratch_pool
  * for temporary allocations.
  */
 svn_error_t *
-svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
+svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
+                                apr_hash_t **actual_props,
                                 svn_wc__db_t *db,
                                 const char *local_abspath,
                                 const char *propname,



Re: svn commit: r1453925 - in /subversion/trunk/subversion/libsvn_wc: props.c status.c wc_db.c wc_db.h

Posted by Paul Burba <pt...@gmail.com>.
Ignore the previous email, it was sent before it's time.  I just
wanted to say that you need to update the doc strings for the
following (to reflect the removal of arguments):

collect_ignore_patterns
send_unversioned_item
one_child_status

On Thu, Mar 7, 2013 at 10:46 AM,  <rh...@apache.org> wrote:
> Author: rhuijben
> Date: Thu Mar  7 15:46:08 2013
> New Revision: 1453925
>
> URL: http://svn.apache.org/r1453925
> Log:
> Handle 'svn:ignore' and 'svn:global-ignores' values as a single list for
> status processing and for svn_wc_get_ignores2().
>
> This patch simplifies some status code and makes a very expensive check per
> directory that contains unversioned files cheaper.
>
> On my profile working copy with unversioned files in every directory, but
> no local changes this accounts for a +- 6% performance improvement on
> 'svn status'
> (The amount of CPU time spend on obtaining these properties was reduced by 50%)
>
> * subversion/libsvn_wc/props.c
>   (svn_wc__get_iprops): Update caller.
>
> * subversion/libsvn_wc/status.c
>   (collect_ignore_patterns): Obtain a single list of patterns. Remove had_props
>     optimization as that doesn't help for inherited properties anyway.
>   (send_unversioned_item,
>    one_child_status,
>    get_dir_status): Remove inherited specialized code.
>
>   (svn_wc_get_ignores2): Update code to really obtain all ignore patterns, as
>     documented.
>
> * subversion/libsvn_wc/wc_db.c
>   (db_read_inherited_props): Add actual_props argument. Constify output array.
>     Use db query directly to calculate whether the parent is what it should be
>     and inherited property eligability with a single query. Obtain actual props
>     if requested.
>     Note that we are not really interested in switched paths here, but just if
>     the parent directory is the parent of the child we are obtaining information
>     for.
>
>   (svn_wc__db_read_inherited_props): Obtain actual_props if requested.
>
> * subversion/libsvn_wc/wc_db.h
>   (svn_wc__db_read_inherited_props): Update documentation and prototype.
>
> Modified:
>     subversion/trunk/subversion/libsvn_wc/props.c
>     subversion/trunk/subversion/libsvn_wc/status.c
>     subversion/trunk/subversion/libsvn_wc/wc_db.c
>     subversion/trunk/subversion/libsvn_wc/wc_db.h
>
> Modified: subversion/trunk/subversion/libsvn_wc/props.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/props.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/props.c Thu Mar  7 15:46:08 2013
> @@ -2314,7 +2314,7 @@ svn_wc__get_iprops(apr_array_header_t **
>                     apr_pool_t *scratch_pool)
>  {
>    return svn_error_trace(
> -            svn_wc__db_read_inherited_props(inherited_props,
> +            svn_wc__db_read_inherited_props(inherited_props, NULL,
>                                              wc_ctx->db, local_abspath,
>                                              propname,
>                                              result_pool, scratch_pool));
>
> Modified: subversion/trunk/subversion/libsvn_wc/status.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/status.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/status.c Thu Mar  7 15:46:08 2013
> @@ -962,17 +962,16 @@ send_status_structure(const struct walk_
>  */
>  static svn_error_t *
>  collect_ignore_patterns(apr_array_header_t **patterns,
> -                        apr_array_header_t **inherited_patterns,
>                          svn_wc__db_t *db,
>                          const char *local_abspath,
>                          const apr_array_header_t *ignores,
> -                        svn_boolean_t may_have_props,
>                          apr_pool_t *result_pool,
>                          apr_pool_t *scratch_pool)
>  {
>    int i;
> -  const svn_string_t *value;
> -  apr_hash_t *props = NULL;
> +  apr_hash_t *props;
> +  const apr_array_header_t *inherited_props;
> +  svn_error_t *err;
>
>    /* ### assert we are passed a directory? */
>
> @@ -986,56 +985,46 @@ collect_ignore_patterns(apr_array_header
>                                                              ignore);
>      }
>
> -  if (may_have_props)
> +  err = svn_wc__db_read_inherited_props(&inherited_props, &props,
> +                                        db, local_abspath,
> +                                        SVN_PROP_INHERITABLE_IGNORES,
> +                                        scratch_pool, scratch_pool);
> +
> +  if (err)
>      {
> -      /* Add any svn:ignore globs to the PATTERNS array. */
> -      SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
> -                                    scratch_pool, scratch_pool));
> +      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
> +        return svn_error_trace(err);
>
> -      if (!props)
> -        return SVN_NO_ERROR;
> +      svn_error_clear(err);
> +      return SVN_NO_ERROR;
> +    }
> +
> +  if (props)
> +    {
> +      const svn_string_t *value;
>
> -      value = apr_hash_get(props, SVN_PROP_IGNORE, APR_HASH_KEY_STRING);
> +      value = svn_hash_gets(props, SVN_PROP_IGNORE);
> +      if (value)
> +        svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
> +                                 result_pool);
>
> -      if (value != NULL)
> +      value = svn_hash_gets(props, SVN_PROP_INHERITABLE_IGNORES);
> +      if (value)
>          svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
>                                   result_pool);
>      }
>
> -  if (inherited_patterns)
> +  for (i = 0; i < inherited_props->nelts; i++)
>      {
> -      apr_array_header_t *inherited_props;
> +      svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
> +        inherited_props, i, svn_prop_inherited_item_t *);
> +      const svn_string_t *value;
>
> -      *inherited_patterns = apr_array_make(result_pool, 1,
> -                                           sizeof(const char *));
> -      if (props)
> -        {
> -          value = apr_hash_get(props, SVN_PROP_INHERITABLE_IGNORES,
> -                               APR_HASH_KEY_STRING);
> -          if (value != NULL)
> -            svn_cstring_split_append(*inherited_patterns, value->data, "\n\r",
> -                                     FALSE, result_pool);
> -        }
> -
> -      SVN_ERR(svn_wc__db_read_inherited_props(&inherited_props,
> -                                              db, local_abspath,
> -                                              SVN_PROP_INHERITABLE_IGNORES,
> -                                              scratch_pool, scratch_pool));
> -      for (i = 0; i < inherited_props->nelts; i++)
> -        {
> -          apr_hash_index_t *hi;
> -          svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
> -            inherited_props, i, svn_prop_inherited_item_t *);
> -
> -          for (hi = apr_hash_first(scratch_pool, elt->prop_hash);
> -               hi;
> -               hi = apr_hash_next(hi))
> -            {
> -              const svn_string_t *propval = svn__apr_hash_index_val(hi);
> -              svn_cstring_split_append(*inherited_patterns, propval->data,
> -                                       "\n\r", FALSE, result_pool);
> -            }
> -        }
> +      value = svn_hash_gets(elt->prop_hash, SVN_PROP_INHERITABLE_IGNORES);
> +
> +      if (value)
> +        svn_cstring_split_append(*patterns, value->data,
> +                                 "\n\r", FALSE, result_pool);
>      }
>
>    return SVN_NO_ERROR;
> @@ -1097,26 +1086,21 @@ send_unversioned_item(const struct walk_
>                        const svn_io_dirent2_t *dirent,
>                        svn_boolean_t tree_conflicted,
>                        const apr_array_header_t *patterns,
> -                      const apr_array_header_t *inherited_patterns,
>                        svn_boolean_t no_ignore,
>                        svn_wc_status_func4_t status_func,
>                        void *status_baton,
>                        apr_pool_t *scratch_pool)
>  {
>    svn_boolean_t is_ignored;
> -  svn_boolean_t is_mandatory_ignored;
>    svn_boolean_t is_external;
>    svn_wc_status3_t *status;
>    const char *base_name = svn_dirent_basename(local_abspath, NULL);
>
>    is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool);
> -  is_mandatory_ignored = svn_wc_match_ignore_list(base_name,
> -                                                  inherited_patterns,
> -                                                  scratch_pool);
>    SVN_ERR(assemble_unversioned(&status,
>                                 wb->db, local_abspath,
>                                 dirent, tree_conflicted,
> -                               is_ignored || is_mandatory_ignored,
> +                               is_ignored,
>                                 scratch_pool, scratch_pool));
>
>    is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
> @@ -1132,7 +1116,7 @@ send_unversioned_item(const struct walk_
>    /* If we aren't ignoring it, or if it's an externals path, pass this
>       entry to the status func. */
>    if (no_ignore
> -      || !(is_ignored || is_mandatory_ignored)
> +      || !is_ignored
>        || is_external)
>      return svn_error_trace((*status_func)(status_baton, local_abspath,
>                                            status, scratch_pool));
> @@ -1181,20 +1165,18 @@ get_dir_status(const struct walk_status_
>   *
>   * DIR_HAS_PROPS is a boolean indicating whether PARENT_ABSPATH has properties.
>   *
> - * If *COLLECTED_IGNORE_PATTERNS or COLLECTED_INHERITED_IGNORE_PATTERNS are NULL
> - * and ignore patterns are needed in this call, then *COLLECTED_IGNORE_PATTERNS
> - * *COLLECTED_INHERITED_IGNORE_PATTERNS will be set to an apr_array_header_t*
> + * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in this
> + * call, then *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t*
>   * containing all ignore patterns, as returned by collect_ignore_patterns() on
> - * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS and
> - * COLLECTED_INHERITED_IGNORE_PATTERNS is passed non-NULL, it is assumed they
> - * already hold those results. This speeds up repeated calls with the same
> - * PARENT_ABSPATH.
> + * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed
> + *  non-NULL, it is assumed it already holds those results.
> + * This speeds up repeated calls with the same PARENT_ABSPATH.
>   *
> - * *COLLECTED_IGNORE_PATTERNS and COLLECTED_INHERITED_IGNORE_PATTERNS will be
> - * allocated in RESULT_POOL. All other allocations are made in SCRATCH_POOL.
> + * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other
> + * allocations are made in SCRATCH_POOL.
>   *
>   * The remaining parameters correspond to get_dir_status(). */
> -static svn_error_t*
> +static svn_error_t *
>  one_child_status(const struct walk_status_baton *wb,
>                   const char *local_abspath,
>                   const char *parent_abspath,
> @@ -1203,10 +1185,8 @@ one_child_status(const struct walk_statu
>                   const char *dir_repos_root_url,
>                   const char *dir_repos_relpath,
>                   const char *dir_repos_uuid,
> -                 svn_boolean_t dir_has_props,
>                   svn_boolean_t unversioned_tree_conflicted,
>                   apr_array_header_t **collected_ignore_patterns,
> -                 apr_array_header_t **collected_inherited_ignore_patterns,
>                   const apr_array_header_t *ignore_patterns,
>                   svn_depth_t depth,
>                   svn_boolean_t get_all,
> @@ -1289,13 +1269,9 @@ one_child_status(const struct walk_statu
>     * determined.  For example, in 'svn status', plain unversioned nodes show
>     * as '?  C', where ignored ones show as 'I  C'. */
>
> -  if ((ignore_patterns && ! *collected_ignore_patterns)
> -      || (collected_inherited_ignore_patterns
> -          && ! collected_inherited_ignore_patterns))
> +  if (ignore_patterns && ! *collected_ignore_patterns)
>      SVN_ERR(collect_ignore_patterns(collected_ignore_patterns,
> -                                    collected_inherited_ignore_patterns,
>                                      wb->db, parent_abspath, ignore_patterns,
> -                                    dir_has_props,
>                                      result_pool, scratch_pool));
>
>    SVN_ERR(send_unversioned_item(wb,
> @@ -1303,7 +1279,6 @@ one_child_status(const struct walk_statu
>                                  dirent,
>                                  conflicted,
>                                  *collected_ignore_patterns,
> -                                *collected_inherited_ignore_patterns,
>                                  no_ignore,
>                                  status_func, status_baton,
>                                  scratch_pool));
> @@ -1357,7 +1332,6 @@ get_dir_status(const struct walk_status_
>    apr_hash_t *dirents, *nodes, *conflicts, *all_children;
>    apr_array_header_t *sorted_children;
>    apr_array_header_t *collected_ignore_patterns = NULL;
> -  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
>    apr_pool_t *iterpool;
>    svn_error_t *err;
>    int i;
> @@ -1486,10 +1460,8 @@ get_dir_status(const struct walk_status_
>                                 dir_repos_root_url,
>                                 dir_repos_relpath,
>                                 dir_repos_uuid,
> -                               dir_has_props,
>                                 apr_hash_get(conflicts, key, klen) != NULL,
>                                 &collected_ignore_patterns,
> -                               &collected_inherited_ignore_patterns,
>                                 ignore_patterns,
>                                 depth,
>                                 get_all,
> @@ -1539,7 +1511,6 @@ get_child_status(const struct walk_statu
>    const char *dir_repos_uuid;
>    const struct svn_wc__db_info_t *dir_info;
>    apr_array_header_t *collected_ignore_patterns = NULL;
> -  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
>    const char *parent_abspath = svn_dirent_dirname(local_abspath,
>                                                    scratch_pool);
>
> @@ -1571,10 +1542,8 @@ get_child_status(const struct walk_statu
>                             dir_repos_root_url,
>                             dir_repos_relpath,
>                             dir_repos_uuid,
> -                           (dir_info->had_props || dir_info->props_mod),
>                             FALSE, /* unversioned_tree_conflicted */
>                             &collected_ignore_patterns,
> -                           &collected_inherited_ignore_patterns,
>                             ignore_patterns,
>                             svn_depth_empty,
>                             get_all,
> @@ -3092,8 +3061,8 @@ svn_wc_get_ignores2(apr_array_header_t *
>    apr_array_header_t *default_ignores;
>
>    SVN_ERR(svn_wc_get_default_ignores(&default_ignores, config, scratch_pool));
> -  return svn_error_trace(collect_ignore_patterns(patterns, NULL, wc_ctx->db,
> +  return svn_error_trace(collect_ignore_patterns(patterns, wc_ctx->db,
>                                                   local_abspath,
> -                                                 default_ignores, TRUE,
> +                                                 default_ignores,
>                                                   result_pool, scratch_pool));
>  }
>
> Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Mar  7 15:46:08 2013
> @@ -9641,7 +9641,8 @@ filter_unwanted_props(apr_hash_t *prop_h
>  /* The body of svn_wc__db_read_inherited_props().
>   */
>  static svn_error_t *
> -db_read_inherited_props(apr_array_header_t **iprops,
> +db_read_inherited_props(const apr_array_header_t **inherited_props,
> +                        apr_hash_t **actual_props,
>                          svn_wc__db_wcroot_t *wcroot,
>                          const char *local_relpath,
>                          const char *propname,
> @@ -9650,54 +9651,112 @@ db_read_inherited_props(apr_array_header
>  {
>    int i;
>    apr_array_header_t *cached_iprops = NULL;
> -  const char *parent_relpath = local_relpath;
> -  svn_boolean_t is_wc_root = FALSE;
> +  apr_array_header_t *iprops;
>    apr_pool_t *iterpool = svn_pool_create(scratch_pool);
> +  svn_sqlite__stmt_t *stmt;
> +  apr_hash_t *props = NULL;
> +  const char *relpath;
> +  const char *expected_parent_repos_relpath = NULL;
> +  const char *parent_relpath;
>
> -  *iprops = apr_array_make(result_pool, 1,
> +  iprops = apr_array_make(result_pool, 1,
>                             sizeof(svn_prop_inherited_item_t *));
> +  *inherited_props = iprops;
> +
> +  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
> +                                    STMT_SELECT_NODE_INFO));
> +
> +  relpath = local_relpath;
>
>    /* Walk up to the root of the WC looking for inherited properties.  When we
>       reach the WC root also check for cached inherited properties. */
> -  while (TRUE)
> +  for (relpath = local_relpath; relpath; relpath = parent_relpath)
>      {
>        apr_hash_t *actual_props;
> -      svn_boolean_t is_switched;
> +      svn_boolean_t have_row;
> +      int op_depth;
> +      svn_wc__db_status_t status;
> +
> +      parent_relpath = relpath[0] ? svn_relpath_dirname(relpath, scratch_pool)
> +                                  : NULL;
>
>        svn_pool_clear(iterpool);
>
> -      if (*parent_relpath == '\0')
> +      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, relpath));
> +
> +      SVN_ERR(svn_sqlite__step(&have_row, stmt));
> +
> +      if (!have_row)
> +        return svn_error_createf(
> +                    SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
> +                    _("The node '%s' was not found."),
> +                    path_for_error_message(wcroot, relpath,
> +                                           scratch_pool));
> +
> +      op_depth = svn_sqlite__column_int(stmt, 0);
> +
> +      status = svn_sqlite__column_token(stmt, 3, presence_map);
> +
> +      if (status != svn_wc__db_status_normal
> +          && status != svn_wc__db_status_incomplete)
> +        return svn_error_createf(
> +                    SVN_ERR_WC_PATH_UNEXPECTED_STATUS, svn_sqlite__reset(stmt),
> +                    _("The node '%s' has a status that has no properties."),
> +                    path_for_error_message(wcroot, relpath,
> +                                           scratch_pool));
> +
> +      if (op_depth > 0)
>          {
> -          is_switched = FALSE;
> -          is_wc_root = TRUE;
> +          /* WORKING node. Nothing to check */
>          }
> -      else
> -        SVN_ERR(db_is_switched(&is_switched, NULL, wcroot, parent_relpath,
> -                               scratch_pool));
> +      else if (expected_parent_repos_relpath)
> +        {
> +          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
>
> -      if (is_switched || is_wc_root)
> +          if (strcmp(expected_parent_repos_relpath, repos_relpath) != 0)
> +            {
> +              /* The child of this node has a different parent than this node
> +                 (It is "switched"), so we can stop here. Note that switched
> +                 with the same parent is not interesting for us here. */
> +              SVN_ERR(svn_sqlite__reset(stmt));
> +              break;
> +            }
> +
> +          expected_parent_repos_relpath =
> +              svn_relpath_dirname(expected_parent_repos_relpath, scratch_pool);
> +        }
> +      else
>          {
> -          is_wc_root = TRUE;
> +          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
>
> -          /* If the WC root is also the root of the repository then by
> -             definition there are no inheritable properties to be had,
> -             but checking for that is just as expensive as fetching them
> -             anyway. */
> +          expected_parent_repos_relpath =
> +              svn_relpath_dirname(repos_relpath, scratch_pool);
> +        }
>
> -          /* Grab the cached inherited properties for the WC root. */
> -          SVN_ERR(db_read_cached_iprops(&cached_iprops,
> -                                        wcroot, parent_relpath,
> -                                        result_pool, iterpool));
> +      if (op_depth == 0
> +          && !svn_sqlite__column_is_null(stmt, 16))
> +        {
> +          /* The node contains a cache. No reason to look further */
> +          SVN_ERR(svn_sqlite__column_iprops(&cached_iprops, stmt, 16,
> +                                            result_pool, iterpool));
> +
> +          parent_relpath = NULL; /* Stop after this */
>          }
>
> -      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
> -         LOCAL_ABSPATH can inherit properties from it. */
> -      if (strcmp(local_relpath, parent_relpath) != 0)
> +      if (relpath == local_relpath && actual_props)
> +        SVN_ERR(svn_sqlite__column_properties(&props, stmt, 14,
> +                                              result_pool, scratch_pool));
> +
> +      SVN_ERR(svn_sqlite__reset(stmt));
> +
> +      /* If PARENT_ABSPATH is a parent of LOCAL_ABSPATH, then LOCAL_ABSPATH
> +         can inherit properties from it. */
> +      if (relpath != local_relpath)
>          {
> -          SVN_ERR(db_read_props(&actual_props, wcroot, parent_relpath,
> +          SVN_ERR(db_read_props(&actual_props, wcroot, relpath,
>                                  result_pool, iterpool));
>
> -          if (actual_props)
> +          if (actual_props && apr_hash_count(actual_props))
>              {
>                /* If we only want PROPNAME filter out any other properties. */
>                if (propname)
> @@ -9709,22 +9768,15 @@ db_read_inherited_props(apr_array_header
>                      apr_pcalloc(result_pool,
>                                  sizeof(svn_prop_inherited_item_t));
>                    iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
> -                                                           parent_relpath,
> +                                                           relpath,
>                                                             result_pool);
>
>                    iprop_elt->prop_hash = actual_props;
>                    /* Build the output array in depth-first order. */
> -                  svn_sort__array_insert(&iprop_elt, *iprops, 0);
> +                  svn_sort__array_insert(&iprop_elt, iprops, 0);
>                  }
>              }
>          }
> -
> -      /* Inheritance only goes as far as the nearest WC root. */
> -      if (is_wc_root)
> -        break;
> -
> -      /* Keep looking for the WC root. */
> -      parent_relpath = svn_relpath_dirname(parent_relpath, scratch_pool);
>      }
>
>    if (cached_iprops)
> @@ -9745,16 +9797,34 @@ db_read_inherited_props(apr_array_header
>
>            /* If we didn't filter everything then keep this iprop. */
>            if (apr_hash_count(cached_iprop->prop_hash))
> -            svn_sort__array_insert(&cached_iprop, *iprops, 0);
> +            svn_sort__array_insert(&cached_iprop, iprops, 0);
>          }
>      }
>
> +  if (actual_props)
> +    {
> +      svn_boolean_t have_row;
> +      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
> +                                    STMT_SELECT_ACTUAL_PROPS));
> +      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
> +      SVN_ERR(svn_sqlite__step(&have_row, stmt));
> +
> +      if (have_row && !svn_sqlite__column_is_null(stmt, 0))
> +        SVN_ERR(svn_sqlite__column_properties(actual_props, stmt, 0,
> +                                              result_pool, iterpool));
> +      else
> +        *actual_props = props; /* Cached when we read that record */
> +
> +      SVN_ERR(svn_sqlite__reset(stmt));
> +    }
> +
>    svn_pool_destroy(iterpool);
>    return SVN_NO_ERROR;
>  }
>
>  svn_error_t *
> -svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
> +svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
> +                                apr_hash_t **actual_props,
>                                  svn_wc__db_t *db,
>                                  const char *local_abspath,
>                                  const char *propname,
> @@ -9771,7 +9841,7 @@ svn_wc__db_read_inherited_props(apr_arra
>                                                  scratch_pool, scratch_pool));
>    VERIFY_USABLE_WCROOT(wcroot);
>
> -  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops,
> +  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops, actual_props,
>                                                wcroot, local_relpath, propname,
>                                                result_pool, scratch_pool),
>                        wcroot);
>
> Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
> +++ subversion/trunk/subversion/libsvn_wc/wc_db.h Thu Mar  7 15:46:08 2013
> @@ -2120,11 +2120,15 @@ svn_wc__db_read_pristine_props(apr_hash_
>   * paths relative to the repository root URL for cached inherited
>   * properties and absolute working copy paths otherwise.
>   *
> + * If ACTUAL_PROPS is not NULL, then set *ACTUAL_PROPS to the actual
> + * properties stored on LOCAL_ABSPATH.
> + *
>   * Allocate @a *iprops in @a result_pool.  Use @a scratch_pool
>   * for temporary allocations.
>   */
>  svn_error_t *
> -svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
> +svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
> +                                apr_hash_t **actual_props,
>                                  svn_wc__db_t *db,
>                                  const char *local_abspath,
>                                  const char *propname,
>
>



-- 
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba

Re: svn commit: r1453925 - in /subversion/trunk/subversion/libsvn_wc: props.c status.c wc_db.c wc_db.h

Posted by Paul Burba <pt...@gmail.com>.
On Thu, Mar 7, 2013 at 10:46 AM,  <rh...@apache.org> wrote:
> Author: rhuijben
> Date: Thu Mar  7 15:46:08 2013
> New Revision: 1453925
>
> URL: http://svn.apache.org/r1453925
> Log:
> Handle 'svn:ignore' and 'svn:global-ignores' values as a single list for
> status processing and for svn_wc_get_ignores2().
>
> This patch simplifies some status code and makes a very expensive check per
> directory that contains unversioned files cheaper.
>
> On my profile working copy with unversioned files in every directory, but
> no local changes this accounts for a +- 6% performance improvement on
> 'svn status'
> (The amount of CPU time spend on obtaining these properties was reduced by 50%)
>
> * subversion/libsvn_wc/props.c
>   (svn_wc__get_iprops): Update caller.
>
> * subversion/libsvn_wc/status.c
>   (collect_ignore_patterns): Obtain a single list of patterns. Remove had_props
>     optimization as that doesn't help for inherited properties anyway.
>   (send_unversioned_item,
>    one_child_status,
>    get_dir_status): Remove inherited specialized code.
>
>   (svn_wc_get_ignores2): Update code to really obtain all ignore patterns, as
>     documented.
>
> * subversion/libsvn_wc/wc_db.c
>   (db_read_inherited_props): Add actual_props argument. Constify output array.
>     Use db query directly to calculate whether the parent is what it should be
>     and inherited property eligability with a single query. Obtain actual props
>     if requested.
>     Note that we are not really interested in switched paths here, but just if
>     the parent directory is the parent of the child we are obtaining information
>     for.
>
>   (svn_wc__db_read_inherited_props): Obtain actual_props if requested.
>
> * subversion/libsvn_wc/wc_db.h
>   (svn_wc__db_read_inherited_props): Update documentation and prototype.
>
> Modified:
>     subversion/trunk/subversion/libsvn_wc/props.c
>     subversion/trunk/subversion/libsvn_wc/status.c
>     subversion/trunk/subversion/libsvn_wc/wc_db.c
>     subversion/trunk/subversion/libsvn_wc/wc_db.h
>
> Modified: subversion/trunk/subversion/libsvn_wc/props.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/props.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/props.c Thu Mar  7 15:46:08 2013
> @@ -2314,7 +2314,7 @@ svn_wc__get_iprops(apr_array_header_t **
>                     apr_pool_t *scratch_pool)
>  {
>    return svn_error_trace(
> -            svn_wc__db_read_inherited_props(inherited_props,
> +            svn_wc__db_read_inherited_props(inherited_props, NULL,
>                                              wc_ctx->db, local_abspath,
>                                              propname,
>                                              result_pool, scratch_pool));
>
> Modified: subversion/trunk/subversion/libsvn_wc/status.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/status.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/status.c Thu Mar  7 15:46:08 2013
> @@ -962,17 +962,16 @@ send_status_structure(const struct walk_
>  */
>  static svn_error_t *
>  collect_ignore_patterns(apr_array_header_t **patterns,
> -                        apr_array_header_t **inherited_patterns,
>                          svn_wc__db_t *db,
>                          const char *local_abspath,
>                          const apr_array_header_t *ignores,
> -                        svn_boolean_t may_have_props,
>                          apr_pool_t *result_pool,
>                          apr_pool_t *scratch_pool)
>  {
>    int i;
> -  const svn_string_t *value;
> -  apr_hash_t *props = NULL;
> +  apr_hash_t *props;
> +  const apr_array_header_t *inherited_props;
> +  svn_error_t *err;
>
>    /* ### assert we are passed a directory? */
>
> @@ -986,56 +985,46 @@ collect_ignore_patterns(apr_array_header
>                                                              ignore);
>      }
>
> -  if (may_have_props)
> +  err = svn_wc__db_read_inherited_props(&inherited_props, &props,
> +                                        db, local_abspath,
> +                                        SVN_PROP_INHERITABLE_IGNORES,
> +                                        scratch_pool, scratch_pool);
> +
> +  if (err)
>      {
> -      /* Add any svn:ignore globs to the PATTERNS array. */
> -      SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
> -                                    scratch_pool, scratch_pool));
> +      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
> +        return svn_error_trace(err);
>
> -      if (!props)
> -        return SVN_NO_ERROR;
> +      svn_error_clear(err);
> +      return SVN_NO_ERROR;
> +    }
> +
> +  if (props)
> +    {
> +      const svn_string_t *value;
>
> -      value = apr_hash_get(props, SVN_PROP_IGNORE, APR_HASH_KEY_STRING);
> +      value = svn_hash_gets(props, SVN_PROP_IGNORE);
> +      if (value)
> +        svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
> +                                 result_pool);
>
> -      if (value != NULL)
> +      value = svn_hash_gets(props, SVN_PROP_INHERITABLE_IGNORES);
> +      if (value)
>          svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
>                                   result_pool);
>      }
>
> -  if (inherited_patterns)
> +  for (i = 0; i < inherited_props->nelts; i++)
>      {
> -      apr_array_header_t *inherited_props;
> +      svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
> +        inherited_props, i, svn_prop_inherited_item_t *);
> +      const svn_string_t *value;
>
> -      *inherited_patterns = apr_array_make(result_pool, 1,
> -                                           sizeof(const char *));
> -      if (props)
> -        {
> -          value = apr_hash_get(props, SVN_PROP_INHERITABLE_IGNORES,
> -                               APR_HASH_KEY_STRING);
> -          if (value != NULL)
> -            svn_cstring_split_append(*inherited_patterns, value->data, "\n\r",
> -                                     FALSE, result_pool);
> -        }
> -
> -      SVN_ERR(svn_wc__db_read_inherited_props(&inherited_props,
> -                                              db, local_abspath,
> -                                              SVN_PROP_INHERITABLE_IGNORES,
> -                                              scratch_pool, scratch_pool));
> -      for (i = 0; i < inherited_props->nelts; i++)
> -        {
> -          apr_hash_index_t *hi;
> -          svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
> -            inherited_props, i, svn_prop_inherited_item_t *);
> -
> -          for (hi = apr_hash_first(scratch_pool, elt->prop_hash);
> -               hi;
> -               hi = apr_hash_next(hi))
> -            {
> -              const svn_string_t *propval = svn__apr_hash_index_val(hi);
> -              svn_cstring_split_append(*inherited_patterns, propval->data,
> -                                       "\n\r", FALSE, result_pool);
> -            }
> -        }
> +      value = svn_hash_gets(elt->prop_hash, SVN_PROP_INHERITABLE_IGNORES);
> +
> +      if (value)
> +        svn_cstring_split_append(*patterns, value->data,
> +                                 "\n\r", FALSE, result_pool);
>      }
>
>    return SVN_NO_ERROR;
> @@ -1097,26 +1086,21 @@ send_unversioned_item(const struct walk_
>                        const svn_io_dirent2_t *dirent,
>                        svn_boolean_t tree_conflicted,
>                        const apr_array_header_t *patterns,
> -                      const apr_array_header_t *inherited_patterns,
>                        svn_boolean_t no_ignore,
>                        svn_wc_status_func4_t status_func,
>                        void *status_baton,
>                        apr_pool_t *scratch_pool)
>  {
>    svn_boolean_t is_ignored;
> -  svn_boolean_t is_mandatory_ignored;
>    svn_boolean_t is_external;
>    svn_wc_status3_t *status;
>    const char *base_name = svn_dirent_basename(local_abspath, NULL);
>
>    is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool);
> -  is_mandatory_ignored = svn_wc_match_ignore_list(base_name,
> -                                                  inherited_patterns,
> -                                                  scratch_pool);
>    SVN_ERR(assemble_unversioned(&status,
>                                 wb->db, local_abspath,
>                                 dirent, tree_conflicted,
> -                               is_ignored || is_mandatory_ignored,
> +                               is_ignored,
>                                 scratch_pool, scratch_pool));
>
>    is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
> @@ -1132,7 +1116,7 @@ send_unversioned_item(const struct walk_
>    /* If we aren't ignoring it, or if it's an externals path, pass this
>       entry to the status func. */
>    if (no_ignore
> -      || !(is_ignored || is_mandatory_ignored)
> +      || !is_ignored
>        || is_external)
>      return svn_error_trace((*status_func)(status_baton, local_abspath,
>                                            status, scratch_pool));
> @@ -1181,20 +1165,18 @@ get_dir_status(const struct walk_status_
>   *
>   * DIR_HAS_PROPS is a boolean indicating whether PARENT_ABSPATH has properties.
>   *
> - * If *COLLECTED_IGNORE_PATTERNS or COLLECTED_INHERITED_IGNORE_PATTERNS are NULL
> - * and ignore patterns are needed in this call, then *COLLECTED_IGNORE_PATTERNS
> - * *COLLECTED_INHERITED_IGNORE_PATTERNS will be set to an apr_array_header_t*
> + * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in this
> + * call, then *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t*
>   * containing all ignore patterns, as returned by collect_ignore_patterns() on
> - * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS and
> - * COLLECTED_INHERITED_IGNORE_PATTERNS is passed non-NULL, it is assumed they
> - * already hold those results. This speeds up repeated calls with the same
> - * PARENT_ABSPATH.
> + * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed
> + *  non-NULL, it is assumed it already holds those results.
> + * This speeds up repeated calls with the same PARENT_ABSPATH.
>   *
> - * *COLLECTED_IGNORE_PATTERNS and COLLECTED_INHERITED_IGNORE_PATTERNS will be
> - * allocated in RESULT_POOL. All other allocations are made in SCRATCH_POOL.
> + * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other
> + * allocations are made in SCRATCH_POOL.
>   *
>   * The remaining parameters correspond to get_dir_status(). */
> -static svn_error_t*
> +static svn_error_t *
>  one_child_status(const struct walk_status_baton *wb,
>                   const char *local_abspath,
>                   const char *parent_abspath,
> @@ -1203,10 +1185,8 @@ one_child_status(const struct walk_statu
>                   const char *dir_repos_root_url,
>                   const char *dir_repos_relpath,
>                   const char *dir_repos_uuid,
> -                 svn_boolean_t dir_has_props,
>                   svn_boolean_t unversioned_tree_conflicted,
>                   apr_array_header_t **collected_ignore_patterns,
> -                 apr_array_header_t **collected_inherited_ignore_patterns,
>                   const apr_array_header_t *ignore_patterns,
>                   svn_depth_t depth,
>                   svn_boolean_t get_all,
> @@ -1289,13 +1269,9 @@ one_child_status(const struct walk_statu
>     * determined.  For example, in 'svn status', plain unversioned nodes show
>     * as '?  C', where ignored ones show as 'I  C'. */
>
> -  if ((ignore_patterns && ! *collected_ignore_patterns)
> -      || (collected_inherited_ignore_patterns
> -          && ! collected_inherited_ignore_patterns))
> +  if (ignore_patterns && ! *collected_ignore_patterns)
>      SVN_ERR(collect_ignore_patterns(collected_ignore_patterns,
> -                                    collected_inherited_ignore_patterns,
>                                      wb->db, parent_abspath, ignore_patterns,
> -                                    dir_has_props,
>                                      result_pool, scratch_pool));
>
>    SVN_ERR(send_unversioned_item(wb,
> @@ -1303,7 +1279,6 @@ one_child_status(const struct walk_statu
>                                  dirent,
>                                  conflicted,
>                                  *collected_ignore_patterns,
> -                                *collected_inherited_ignore_patterns,
>                                  no_ignore,
>                                  status_func, status_baton,
>                                  scratch_pool));
> @@ -1357,7 +1332,6 @@ get_dir_status(const struct walk_status_
>    apr_hash_t *dirents, *nodes, *conflicts, *all_children;
>    apr_array_header_t *sorted_children;
>    apr_array_header_t *collected_ignore_patterns = NULL;
> -  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
>    apr_pool_t *iterpool;
>    svn_error_t *err;
>    int i;
> @@ -1486,10 +1460,8 @@ get_dir_status(const struct walk_status_
>                                 dir_repos_root_url,
>                                 dir_repos_relpath,
>                                 dir_repos_uuid,
> -                               dir_has_props,
>                                 apr_hash_get(conflicts, key, klen) != NULL,
>                                 &collected_ignore_patterns,
> -                               &collected_inherited_ignore_patterns,
>                                 ignore_patterns,
>                                 depth,
>                                 get_all,
> @@ -1539,7 +1511,6 @@ get_child_status(const struct walk_statu
>    const char *dir_repos_uuid;
>    const struct svn_wc__db_info_t *dir_info;
>    apr_array_header_t *collected_ignore_patterns = NULL;
> -  apr_array_header_t *collected_inherited_ignore_patterns = NULL;
>    const char *parent_abspath = svn_dirent_dirname(local_abspath,
>                                                    scratch_pool);
>
> @@ -1571,10 +1542,8 @@ get_child_status(const struct walk_statu
>                             dir_repos_root_url,
>                             dir_repos_relpath,
>                             dir_repos_uuid,
> -                           (dir_info->had_props || dir_info->props_mod),
>                             FALSE, /* unversioned_tree_conflicted */
>                             &collected_ignore_patterns,
> -                           &collected_inherited_ignore_patterns,
>                             ignore_patterns,
>                             svn_depth_empty,
>                             get_all,
> @@ -3092,8 +3061,8 @@ svn_wc_get_ignores2(apr_array_header_t *
>    apr_array_header_t *default_ignores;
>
>    SVN_ERR(svn_wc_get_default_ignores(&default_ignores, config, scratch_pool));
> -  return svn_error_trace(collect_ignore_patterns(patterns, NULL, wc_ctx->db,
> +  return svn_error_trace(collect_ignore_patterns(patterns, wc_ctx->db,
>                                                   local_abspath,
> -                                                 default_ignores, TRUE,
> +                                                 default_ignores,
>                                                   result_pool, scratch_pool));
>  }
>
> Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
> +++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Mar  7 15:46:08 2013
> @@ -9641,7 +9641,8 @@ filter_unwanted_props(apr_hash_t *prop_h
>  /* The body of svn_wc__db_read_inherited_props().
>   */
>  static svn_error_t *
> -db_read_inherited_props(apr_array_header_t **iprops,
> +db_read_inherited_props(const apr_array_header_t **inherited_props,
> +                        apr_hash_t **actual_props,
>                          svn_wc__db_wcroot_t *wcroot,
>                          const char *local_relpath,
>                          const char *propname,
> @@ -9650,54 +9651,112 @@ db_read_inherited_props(apr_array_header
>  {
>    int i;
>    apr_array_header_t *cached_iprops = NULL;
> -  const char *parent_relpath = local_relpath;
> -  svn_boolean_t is_wc_root = FALSE;
> +  apr_array_header_t *iprops;
>    apr_pool_t *iterpool = svn_pool_create(scratch_pool);
> +  svn_sqlite__stmt_t *stmt;
> +  apr_hash_t *props = NULL;
> +  const char *relpath;
> +  const char *expected_parent_repos_relpath = NULL;
> +  const char *parent_relpath;
>
> -  *iprops = apr_array_make(result_pool, 1,
> +  iprops = apr_array_make(result_pool, 1,
>                             sizeof(svn_prop_inherited_item_t *));
> +  *inherited_props = iprops;
> +
> +  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
> +                                    STMT_SELECT_NODE_INFO));
> +
> +  relpath = local_relpath;
>
>    /* Walk up to the root of the WC looking for inherited properties.  When we
>       reach the WC root also check for cached inherited properties. */
> -  while (TRUE)
> +  for (relpath = local_relpath; relpath; relpath = parent_relpath)
>      {
>        apr_hash_t *actual_props;
> -      svn_boolean_t is_switched;
> +      svn_boolean_t have_row;
> +      int op_depth;
> +      svn_wc__db_status_t status;
> +
> +      parent_relpath = relpath[0] ? svn_relpath_dirname(relpath, scratch_pool)
> +                                  : NULL;
>
>        svn_pool_clear(iterpool);
>
> -      if (*parent_relpath == '\0')
> +      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, relpath));
> +
> +      SVN_ERR(svn_sqlite__step(&have_row, stmt));
> +
> +      if (!have_row)
> +        return svn_error_createf(
> +                    SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
> +                    _("The node '%s' was not found."),
> +                    path_for_error_message(wcroot, relpath,
> +                                           scratch_pool));
> +
> +      op_depth = svn_sqlite__column_int(stmt, 0);
> +
> +      status = svn_sqlite__column_token(stmt, 3, presence_map);
> +
> +      if (status != svn_wc__db_status_normal
> +          && status != svn_wc__db_status_incomplete)
> +        return svn_error_createf(
> +                    SVN_ERR_WC_PATH_UNEXPECTED_STATUS, svn_sqlite__reset(stmt),
> +                    _("The node '%s' has a status that has no properties."),
> +                    path_for_error_message(wcroot, relpath,
> +                                           scratch_pool));
> +
> +      if (op_depth > 0)
>          {
> -          is_switched = FALSE;
> -          is_wc_root = TRUE;
> +          /* WORKING node. Nothing to check */
>          }
> -      else
> -        SVN_ERR(db_is_switched(&is_switched, NULL, wcroot, parent_relpath,
> -                               scratch_pool));
> +      else if (expected_parent_repos_relpath)
> +        {
> +          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
>
> -      if (is_switched || is_wc_root)
> +          if (strcmp(expected_parent_repos_relpath, repos_relpath) != 0)
> +            {
> +              /* The child of this node has a different parent than this node
> +                 (It is "switched"), so we can stop here. Note that switched
> +                 with the same parent is not interesting for us here. */
> +              SVN_ERR(svn_sqlite__reset(stmt));
> +              break;
> +            }
> +
> +          expected_parent_repos_relpath =
> +              svn_relpath_dirname(expected_parent_repos_relpath, scratch_pool);
> +        }
> +      else
>          {
> -          is_wc_root = TRUE;
> +          const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
>
> -          /* If the WC root is also the root of the repository then by
> -             definition there are no inheritable properties to be had,
> -             but checking for that is just as expensive as fetching them
> -             anyway. */
> +          expected_parent_repos_relpath =
> +              svn_relpath_dirname(repos_relpath, scratch_pool);
> +        }
>
> -          /* Grab the cached inherited properties for the WC root. */
> -          SVN_ERR(db_read_cached_iprops(&cached_iprops,
> -                                        wcroot, parent_relpath,
> -                                        result_pool, iterpool));
> +      if (op_depth == 0
> +          && !svn_sqlite__column_is_null(stmt, 16))
> +        {
> +          /* The node contains a cache. No reason to look further */
> +          SVN_ERR(svn_sqlite__column_iprops(&cached_iprops, stmt, 16,
> +                                            result_pool, iterpool));
> +
> +          parent_relpath = NULL; /* Stop after this */
>          }
>
> -      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
> -         LOCAL_ABSPATH can inherit properties from it. */
> -      if (strcmp(local_relpath, parent_relpath) != 0)
> +      if (relpath == local_relpath && actual_props)
> +        SVN_ERR(svn_sqlite__column_properties(&props, stmt, 14,
> +                                              result_pool, scratch_pool));
> +
> +      SVN_ERR(svn_sqlite__reset(stmt));
> +
> +      /* If PARENT_ABSPATH is a parent of LOCAL_ABSPATH, then LOCAL_ABSPATH
> +         can inherit properties from it. */
> +      if (relpath != local_relpath)
>          {
> -          SVN_ERR(db_read_props(&actual_props, wcroot, parent_relpath,
> +          SVN_ERR(db_read_props(&actual_props, wcroot, relpath,
>                                  result_pool, iterpool));
>
> -          if (actual_props)
> +          if (actual_props && apr_hash_count(actual_props))
>              {
>                /* If we only want PROPNAME filter out any other properties. */
>                if (propname)
> @@ -9709,22 +9768,15 @@ db_read_inherited_props(apr_array_header
>                      apr_pcalloc(result_pool,
>                                  sizeof(svn_prop_inherited_item_t));
>                    iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
> -                                                           parent_relpath,
> +                                                           relpath,
>                                                             result_pool);
>
>                    iprop_elt->prop_hash = actual_props;
>                    /* Build the output array in depth-first order. */
> -                  svn_sort__array_insert(&iprop_elt, *iprops, 0);
> +                  svn_sort__array_insert(&iprop_elt, iprops, 0);
>                  }
>              }
>          }
> -
> -      /* Inheritance only goes as far as the nearest WC root. */
> -      if (is_wc_root)
> -        break;
> -
> -      /* Keep looking for the WC root. */
> -      parent_relpath = svn_relpath_dirname(parent_relpath, scratch_pool);
>      }
>
>    if (cached_iprops)
> @@ -9745,16 +9797,34 @@ db_read_inherited_props(apr_array_header
>
>            /* If we didn't filter everything then keep this iprop. */
>            if (apr_hash_count(cached_iprop->prop_hash))
> -            svn_sort__array_insert(&cached_iprop, *iprops, 0);
> +            svn_sort__array_insert(&cached_iprop, iprops, 0);
>          }
>      }
>
> +  if (actual_props)
> +    {
> +      svn_boolean_t have_row;
> +      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
> +                                    STMT_SELECT_ACTUAL_PROPS));
> +      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
> +      SVN_ERR(svn_sqlite__step(&have_row, stmt));
> +
> +      if (have_row && !svn_sqlite__column_is_null(stmt, 0))
> +        SVN_ERR(svn_sqlite__column_properties(actual_props, stmt, 0,
> +                                              result_pool, iterpool));
> +      else
> +        *actual_props = props; /* Cached when we read that record */
> +
> +      SVN_ERR(svn_sqlite__reset(stmt));
> +    }
> +
>    svn_pool_destroy(iterpool);
>    return SVN_NO_ERROR;
>  }
>
>  svn_error_t *
> -svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
> +svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
> +                                apr_hash_t **actual_props,
>                                  svn_wc__db_t *db,
>                                  const char *local_abspath,
>                                  const char *propname,
> @@ -9771,7 +9841,7 @@ svn_wc__db_read_inherited_props(apr_arra
>                                                  scratch_pool, scratch_pool));
>    VERIFY_USABLE_WCROOT(wcroot);
>
> -  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops,
> +  SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops, actual_props,
>                                                wcroot, local_relpath, propname,
>                                                result_pool, scratch_pool),
>                        wcroot);
>
> Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1453925&r1=1453924&r2=1453925&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
> +++ subversion/trunk/subversion/libsvn_wc/wc_db.h Thu Mar  7 15:46:08 2013
> @@ -2120,11 +2120,15 @@ svn_wc__db_read_pristine_props(apr_hash_
>   * paths relative to the repository root URL for cached inherited
>   * properties and absolute working copy paths otherwise.
>   *
> + * If ACTUAL_PROPS is not NULL, then set *ACTUAL_PROPS to the actual
> + * properties stored on LOCAL_ABSPATH.
> + *
>   * Allocate @a *iprops in @a result_pool.  Use @a scratch_pool
>   * for temporary allocations.
>   */
>  svn_error_t *
> -svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
> +svn_wc__db_read_inherited_props(const apr_array_header_t **iprops,
> +                                apr_hash_t **actual_props,
>                                  svn_wc__db_t *db,
>                                  const char *local_abspath,
>                                  const char *propname,
>
>



-- 
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba