You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2012/06/26 02:55:11 UTC

svn commit: r1353788 - in /subversion/branches/inheritable-props/subversion: include/private/ libsvn_client/ libsvn_wc/ tests/cmdline/

Author: pburba
Date: Tue Jun 26 00:55:07 2012
New Revision: 1353788

URL: http://svn.apache.org/viewvc?rev=1353788&view=rev
Log:
On the inheritable-props branch: "Checkpoint" of WC-side inherited property
caching.  This is still work-in-progress, notably:

  1) The wcng schema changes for caching iprops is still in flux.

  2) The new private API svn_client__update_inheritable_props is temporary.
     Eventually this logic must be run atomically as a work queue item
     in the update/switch editor drive.

* subversion/include/private/svn_wc_private.h

  (svn_wc__get_iprops,
   svn_wc__cache_iprops,
   svn_wc__delete_iprops,
   svn_wc__get_cached_iprop_children): New.

* subversion/libsvn_client/client.h

  (svn_client__update_inheritable_props): New.

* subversion/libsvn_client/iprops.c:

  (need_to_cache_iprops,
   svn_client__update_inheritable_props): New.

* subversion/libsvn_client/prop_commands.c

  (svn_sorts.h): Include.

  (remote_propget): Allow option to get either explicit or inherited props,
   or both.

  (svn_client_propget5): Enable retrieval of local/cached iprops for WC
   targets.

  (remote_proplist): Allow option to get either explicit or inherited props,
   or both.

  (svn_client_proplist4): Enable retrieval of local/cached iprops for WC
   targets.

* subversion/libsvn_client/switch.c

  (switch_internal): Update inheritable properties cache after a switch.

* subversion/libsvn_client/update.c

  (update_internal): Update inheritable properties cache after an update.

* subversion/libsvn_wc/props.c

  (filter_unwanted_props,
   svn_wc__get_iprops,
   svn_wc__cache_iprops,
   svn_wc__delete_iprops): New.

* subversion/libsvn_wc/update_editor.c

  (svn_wc_is_wc_root2): Do what our doc string promises and consider a
   switched file a WC root.

* subversion/libsvn_wc/wc-metadata.sql

  (STMT_INHERITABLE_PROPS): New inheritable_props table.

* subversion/libsvn_wc/wc-queries.sql

  (STMT_SELECT_IPROPS,
   STMT_INSERT_IPROP,
   STMT_DELETE_IPROPS_RECURSIVE,
   STMT_DELETE_IPROPS,
   STMT_SELECT_INODES,
   STMT_SELECT_INODES_RECURSIVE): New queries against the inheritable_props
   table.

* subversion/libsvn_wc/wc_db.c

  (create_db): Create the inheritable_props table.

  (db_base_remove,
   remove_node_txn): Remove the inheritable_props table.

  (svn_wc__db_read_cached_iprops,
   get_children_with_cached_iprops,
   svn_wc__db_get_children_with_cached_iprops,
   svn_wc__db_remove_cached_iprops): New.

* subversion/libsvn_wc/wc_db.h

  (svn_wc__db_read_cached_iprops,
   svn_wc__db_get_children_with_cached_iprops,
   svn_wc__db_cache_iprops,
   svn_wc__db_remove_cached_iprops): New.

* subversion/tests/cmdline/merge_tests.py

  (merge_to_path_with_switched_children): Tweak merge output to reflect
   fix made to svn_wc_is_wc_root2.

Added:
    subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c   (with props)
Modified:
    subversion/branches/inheritable-props/subversion/include/private/svn_wc_private.h
    subversion/branches/inheritable-props/subversion/libsvn_client/client.h
    subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c
    subversion/branches/inheritable-props/subversion/libsvn_client/switch.c
    subversion/branches/inheritable-props/subversion/libsvn_client/update.c
    subversion/branches/inheritable-props/subversion/libsvn_wc/props.c
    subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c
    subversion/branches/inheritable-props/subversion/libsvn_wc/wc-metadata.sql
    subversion/branches/inheritable-props/subversion/libsvn_wc/wc-queries.sql
    subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.c
    subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.h
    subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py

Modified: subversion/branches/inheritable-props/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/include/private/svn_wc_private.h?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/inheritable-props/subversion/include/private/svn_wc_private.h Tue Jun 26 00:55:07 2012
@@ -922,6 +922,69 @@ svn_wc__prop_list_recursive(svn_wc_conte
                             void *cancel_baton,
                             apr_pool_t *scratch_pool);
 
+/**
+ * Set @a *inherited_props to a depth-first ordered array of
+ * #svn_prop_inherited_item_t * structures representing the properties
+ * inherited by @a local_abspath from the ACTUAL tree above
+ * @a local_abspath (looking through to the WORKING or BASE tree as
+ * required), up to and including the root of the working copy and
+ * any cached inherited properties inherited by the root.  If any
+ * cached inherited properties are found or a working copy parent
+ * representing the repository root is reached, then set
+ * @a *cached_iprops_found to TRUE, set it to FALSE otherwise.
+ *
+ * Allocate @a *inherited_props in @a result_pool.  Use @a scratch_pool
+ * for temporary allocations.
+ */
+svn_error_t *
+svn_wc__get_iprops(apr_array_header_t **inherited_props,
+                   svn_boolean_t *cached_iprops_found,
+                   svn_wc_context_t *wc_ctx,
+                   const char *local_abspath,
+                   const char *propname,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool);
+
+/**
+ * Cache the inherited properties @a inherited_props (a depth-first ordered
+ * array of #svn_prop_inherited_item_t * structures) for the BASE node at
+ * @a local_abspath.  If there is no base node at @a local_abspath, then do
+ * nothing.  If @a local_abspath is not in the working copy, return
+ * @c SVN_ERR_WC_PATH_NOT_FOUND.
+ *
+ * Use @a scratch_pool for temporary allocations.
+ */
+svn_error_t *
+svn_wc__cache_iprops(apr_array_header_t *inherited_props,
+                     svn_wc_context_t *wc_ctx,
+                     const char *local_abspath,
+                     apr_pool_t *scratch_pool);
+
+/**
+ * Delete all cached inherited properties for the BASE node at LOCAL_ABSPATH.
+ *
+ * Use @a scratch_pool for temporary allocations.
+ */
+svn_error_t *
+svn_wc__delete_iprops(svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      apr_pool_t *scratch_pool);
+
+/**
+ * Set @a *iprops_paths to a hash mapping const char * absolute working
+ * copy paths to the same for each path in the working copy at or below
+ * @a local_abspath, limited by @a depth, that has cached inherited
+ * properties for the base node of the path.  Allocate @a *iprop_paths
+ * in @a result_pool.  Use @a scratch_pool for temporary allocations.
+ */
+svn_error_t *
+svn_wc__get_cached_iprop_children(apr_hash_t **iprop_paths,
+                                  svn_depth_t depth,
+                                  svn_wc_context_t *wc_ctx,
+                                  const char *local_abspath,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool);
+
 
 /**
  * For use by entries.c and entries-dump.c to read old-format working copies.

Modified: subversion/branches/inheritable-props/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/client.h?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/client.h (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/client.h Tue Jun 26 00:55:07 2012
@@ -588,6 +588,29 @@ svn_client__switch_internal(svn_revnum_t
 
 /* ---------------------------------------------------------------- */
 
+/*** Inheritable Properties ***/
+
+/* Fetch the inherited properties for the base of LOCAL_ABSPATH using
+   RA_SESSION and cache the results for all WC roots at or under
+   LOCAL_ABSPATH (limited by DEPTH).  If LOCAL_ABSPATH has no base then
+   do nothing.
+
+   RA_SESSION should be an open RA session pointing at the URL of PATH,
+   or NULL, in which case this function will open its own temporary session.
+
+   ### IPROPS: This is a temporary private API.  Eventually this logic must
+   ### be run atomically as a work queue item in the update/switch editor
+   ### drive.
+*/
+svn_error_t *
+svn_client__update_inheritable_props(const char *local_abspath,
+                                     svn_depth_t depth,
+                                     svn_ra_session_t *ra_session,
+                                     svn_client_ctx_t *ctx,
+                                     apr_pool_t *scratch_pool);
+
+/* ---------------------------------------------------------------- */
+
 /*** Editor for repository diff ***/
 
 /* Create an editor for a pure repository comparison, i.e. comparing one

Added: subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c?rev=1353788&view=auto
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c (added)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c Tue Jun 26 00:55:07 2012
@@ -0,0 +1,167 @@
+/*
+ * iprops.c:  wrappers around wc inherited property functionality
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_wc.h"
+#include "svn_ra.h"
+
+#include "client.h"
+#include "svn_private_config.h"
+
+#include "private/svn_wc_private.h"
+
+
+/*** Code. ***/
+
+/* Determine if ABSPATH needs an inherited property cache (i.e. it is a WC
+   root that is not also the repository root or it is switched).  If it does,
+   then set *NEEDS_CACHE to true, set it to false otherwise. */
+static svn_error_t *
+need_to_cache_iprops(svn_boolean_t *needs_cache,
+                     const char *abspath,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t is_wc_root;
+
+  /* Our starting assumption. */
+  *needs_cache = FALSE;
+
+  SVN_ERR(svn_wc_is_wc_root2(&is_wc_root, ctx->wc_ctx, abspath,
+                             scratch_pool));
+
+  if (is_wc_root)
+    {
+      const char *child_repos_relpath;
+
+      /* We want to cache the inherited properties for WC roots, unless that
+         root points to the root of the repository, then there in nowhere to
+         inherit properties from. */
+      SVN_ERR(svn_wc__node_get_repos_relpath(&child_repos_relpath,
+                                             ctx->wc_ctx, abspath,
+                                             scratch_pool, scratch_pool));
+      if (child_repos_relpath[0] != '\0')
+        *needs_cache = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__update_inheritable_props(const char *local_abspath,
+                                     svn_depth_t depth,
+                                     svn_ra_session_t *ra_session,
+                                     svn_client_ctx_t *ctx,
+                                     apr_pool_t *scratch_pool)
+{
+  svn_revnum_t revision;
+
+  SVN_ERR(svn_wc__node_get_base(&revision, NULL, NULL, NULL, ctx->wc_ctx,
+                                local_abspath, scratch_pool, scratch_pool));
+
+  /* If we don't have a base revision for LOCAL_ABSPATH then it can't
+     possibly be a working copy root, nor can it contain any WC roots
+     in the form of switched subtrees.  So there is nothing to cache. */
+  if (SVN_IS_VALID_REVNUM(revision))
+    {
+      apr_hash_t *iprop_paths;
+      apr_hash_index_t *hi;
+      const char *old_session_url = NULL;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+      SVN_ERR(svn_wc__get_cached_iprop_children(&iprop_paths, depth,
+                                                ctx->wc_ctx, local_abspath,
+                                                scratch_pool, iterpool));
+
+      /* Make sure LOCAL_ABSPATH is present. */
+      if (!apr_hash_get(iprop_paths, local_abspath, APR_HASH_KEY_STRING))
+        {
+          const char *target_abspath = apr_pstrdup(scratch_pool,
+                                                   local_abspath);
+          apr_hash_set(iprop_paths, target_abspath, APR_HASH_KEY_STRING,
+                       target_abspath);
+        }
+
+      for (hi = apr_hash_first(scratch_pool, iprop_paths);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *child_abspath = svn__apr_hash_index_key(hi);
+          svn_boolean_t needs_cached_iprops;
+
+          svn_pool_clear(iterpool);
+
+          SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, child_abspath,
+                                       ctx, iterpool));
+
+          if (! needs_cached_iprops)
+            {
+              SVN_ERR(svn_wc__delete_iprops(ctx->wc_ctx, child_abspath,
+                                            iterpool));
+            }
+          else
+            {
+              const char *url;
+              apr_array_header_t *inherited_props;
+
+              SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child_abspath,
+                                           iterpool, iterpool));
+              if (ra_session)
+                {
+                  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                                            ra_session,
+                                                            url,
+                                                            scratch_pool));
+                }
+              else
+                {
+                  SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
+                                                               NULL, url,
+                                                               NULL, NULL,
+                                                               FALSE, TRUE,
+                                                               ctx,
+                                                               scratch_pool));
+                }
+
+              SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
+                                                 "", revision, iterpool));
+              SVN_ERR(svn_wc__cache_iprops(inherited_props, ctx->wc_ctx,
+                                           child_abspath, iterpool));
+            }
+        }
+
+      if (old_session_url)
+        SVN_ERR(svn_ra_reparent(ra_session, old_session_url, iterpool));
+
+      svn_pool_destroy(iterpool);
+    }
+
+  return SVN_NO_ERROR;
+}

Propchange: subversion/branches/inheritable-props/subversion/libsvn_client/iprops.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c Tue Jun 26 00:55:07 2012
@@ -38,6 +38,7 @@
 #include "svn_pools.h"
 #include "svn_props.h"
 #include "svn_hash.h"
+#include "svn_sorts.h"
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
@@ -594,9 +595,9 @@ pristine_or_working_props(apr_hash_t **p
 
 /* Helper for the remote case of svn_client_propget.
  *
- * Get the value of property PROPNAME in REVNUM, using RA_LIB and
- * SESSION.  Store the value ('svn_string_t *') in PROPS, under the
- * path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *').
+ * If PROPS is not null, then get the value of property PROPNAME in REVNUM,
+   using RA_LIB and SESSION.  Store the value ('svn_string_t *') in PROPS,
+   under the path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *').
  *
  * If INHERITED_PROPS is not null, then set *INHERITED_PROPS to a
  * depth-first ordered array of svn_prop_inherited_item_t * structures
@@ -627,7 +628,7 @@ remote_propget(apr_hash_t *props,
                apr_pool_t *scratch_pool)
 {
   apr_hash_t *dirents;
-  apr_hash_t *prop_hash;
+  apr_hash_t *prop_hash = NULL;
   const svn_string_t *val;
   const char *target_full_url =
     svn_path_url_add_component2(target_prefix, target_relative,
@@ -637,15 +638,18 @@ remote_propget(apr_hash_t *props,
     {
       SVN_ERR(svn_ra_get_dir3(ra_session,
                               (depth >= svn_depth_files ? &dirents : NULL),
-                              NULL, &prop_hash, inherited_props,
+                              NULL,
+                              props ? &prop_hash : NULL,
+                              inherited_props,
                               target_relative, revnum, SVN_DIRENT_KIND,
                               scratch_pool));
     }
   else if (kind == svn_node_file)
     {
       SVN_ERR(svn_ra_get_file2(ra_session, target_relative, revnum,
-                               NULL, NULL, &prop_hash, inherited_props,
-                               scratch_pool));
+                               NULL, NULL,
+                               props ? &prop_hash : NULL,
+                               inherited_props, scratch_pool));
     }
   else if (kind == svn_node_none)
     {
@@ -692,7 +696,8 @@ remote_propget(apr_hash_t *props,
       *inherited_props = final_iprops;
     }
 
-  if ((val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING)))
+  if (prop_hash
+      && (val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING)))
     {
       apr_hash_set(props, apr_pstrdup(result_pool, target_full_url),
                    APR_HASH_KEY_STRING, svn_string_dup(val, result_pool));
@@ -836,6 +841,8 @@ svn_client_propget5(apr_hash_t **props,
                     apr_pool_t *scratch_pool)
 {
   svn_revnum_t revnum;
+  svn_boolean_t local_explicit_props;
+  svn_boolean_t local_iprops;
 
   SVN_ERR(error_if_wcprop_name(propname));
   if (!svn_path_is_url(target))
@@ -847,9 +854,19 @@ svn_client_propget5(apr_hash_t **props,
 
   *props = apr_hash_make(result_pool);
 
-  if (! svn_path_is_url(target)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
+  local_explicit_props =
+    (! svn_path_is_url(target)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind));
+
+  local_iprops =
+    (local_explicit_props
+     && (peg_revision->kind == svn_opt_revision_working
+         || peg_revision->kind == svn_opt_revision_unspecified )
+     && (revision->kind == svn_opt_revision_working
+         || revision->kind == svn_opt_revision_unspecified ));
+
+  if (local_explicit_props)
     {
       svn_node_kind_t kind;
       svn_boolean_t pristine;
@@ -883,28 +900,119 @@ svn_client_propget5(apr_hash_t **props,
       else if (err)
         return svn_error_trace(err);
 
+      if (inherited_props && local_iprops)
+        {
+          svn_boolean_t cached_iprops_found;
+
+          SVN_ERR(svn_wc__get_iprops(inherited_props, &cached_iprops_found,
+                                     ctx->wc_ctx, target, propname,
+                                     scratch_pool, scratch_pool));
+        }
+
       SVN_ERR(get_prop_from_wc(*props, propname, target,
                                pristine, kind,
                                depth, changelists, ctx, scratch_pool,
                                result_pool));
     }
-  else
+
+  if ((inherited_props && !local_iprops)
+      || !local_explicit_props)
     {
       const char *url;
       svn_ra_session_t *ra_session;
       svn_node_kind_t kind;
+      svn_opt_revision_t new_operative_rev;
+      svn_opt_revision_t new_peg_rev;
 
-      /* Get an RA plugin for this filesystem object. */
-      SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
-                                               &url, target, NULL,
-                                               peg_revision,
-                                               revision, ctx, scratch_pool));
+      /* Peg or operative revisions may be WC specific for
+         TARGET's explicit props, but still require us to
+         contact the repository for the inherited properties. */
+      if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)
+          || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+        {
+          svn_revnum_t origin_rev;
+          const char *repos_relpath;
+          const char *repos_root_url;
+          const char *repos_uuid;
+          const char *local_abspath;
+          const char *copy_root_abspath;
+          svn_boolean_t is_copy;
+
+          SVN_ERR(svn_dirent_get_absolute(&local_abspath, target,
+                                          scratch_pool));
 
-      SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, scratch_pool));
+          if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+            {
+              SVN_ERR(svn_wc__node_get_origin(&is_copy,
+                                              &origin_rev,
+                                              &repos_relpath,
+                                              &repos_root_url,
+                                              &repos_uuid,
+                                              &copy_root_abspath,
+                                              ctx->wc_ctx,
+                                              local_abspath,
+                                              FALSE, /* scan_deleted */
+                                              result_pool,
+                                              scratch_pool));
+              if (repos_relpath)
+                {
+                  target = svn_path_url_add_component2(repos_root_url,
+                                                       repos_relpath,
+                                                       scratch_pool);
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+                    {
+                      svn_revnum_t resolved_peg_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(
+                        &resolved_peg_rev, NULL, ctx->wc_ctx,
+                        local_abspath, NULL, peg_revision, scratch_pool));
+                      new_peg_rev.kind = svn_opt_revision_number;
+                      new_peg_rev.value.number = resolved_peg_rev;
+                      peg_revision = &new_peg_rev;
+                    }
+
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+                    {
+                      svn_revnum_t resolved_operative_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(
+                        &resolved_operative_rev, NULL, ctx->wc_ctx,
+                        local_abspath, NULL, revision, scratch_pool));
+                      new_operative_rev.kind = svn_opt_revision_number;
+                      new_operative_rev.value.number = resolved_operative_rev;
+                      revision = &new_operative_rev;
+                    }
+                }
+              else
+                {
+                  /* TARGET doesn't exist in the repository, so there are
+                     obviously not inherited props to be found there. */
+                  local_iprops = TRUE;
+                  *inherited_props = apr_array_make(
+                    result_pool, 0, sizeof(svn_prop_inherited_item_t *));
+                }
+            }
+        }
 
-      SVN_ERR(remote_propget(*props, inherited_props, propname, url, "",
-                             kind, revnum, ra_session,
-                             depth, result_pool, scratch_pool));
+      /* Do we still have anything to ask the repository about? */
+      if (!local_explicit_props || !local_iprops)
+        {
+          /* Get an RA plugin for this filesystem object. */
+          SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
+                                                   &url, target, NULL,
+                                                   peg_revision,
+                                                   revision, ctx,
+                                                   scratch_pool));
+
+          SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind,
+                                    scratch_pool));
+
+          SVN_ERR(remote_propget(!local_explicit_props ? *props : NULL,
+                                 !local_iprops ? inherited_props : NULL,
+                                 propname, url, "",
+                                 kind, revnum, ra_session,
+                                 depth, result_pool, scratch_pool));
+        }
     }
 
   if (actual_revnum)
@@ -963,10 +1071,10 @@ call_receiver(const char *path,
 
 /* Helper for the remote case of svn_client_proplist.
  *
- * Call RECEIVER for paths at or under "TARGET_PREFIX/TARGET_RELATIVE@REVNUM"
- * (obtained using RA_SESSION) which have regular properties.  If
- * GET_TARGET_INHERITED_PROPS is true, then also send the target's inherited
- * properties to the callback.
+ * If GET_EXPLICIT_PROPS is true, then call RECEIVER for paths at or under
+ * "TARGET_PREFIX/TARGET_RELATIVE@REVNUM" (obtained using RA_SESSION) which
+ * have regular properties.  If GET_TARGET_INHERITED_PROPS is true, then send
+ * the target's inherited properties to the callback.
  *
  * The 'path' and keys for 'prop_hash' and 'inherited_prop' arguments to
  * RECEIVER are all URLs.
@@ -987,6 +1095,7 @@ remote_proplist(const char *target_prefi
                 svn_node_kind_t kind,
                 svn_revnum_t revnum,
                 svn_ra_session_t *ra_session,
+                svn_boolean_t get_explicit_props,
                 svn_boolean_t get_target_inherited_props,
                 svn_depth_t depth,
                 svn_proplist_receiver2_t receiver,
@@ -995,7 +1104,8 @@ remote_proplist(const char *target_prefi
                 apr_pool_t *scratch_pool)
 {
   apr_hash_t *dirents;
-  apr_hash_t *prop_hash, *final_hash;
+  apr_hash_t *prop_hash = NULL;
+  apr_hash_t *final_hash = NULL;
   apr_hash_index_t *hi;
   const char *target_full_url =
     svn_path_url_add_component2(target_prefix, target_relative, scratch_pool);
@@ -1006,7 +1116,8 @@ remote_proplist(const char *target_prefi
       SVN_ERR(svn_ra_get_dir3(
         ra_session,
         (depth > svn_depth_empty) ? &dirents : NULL,
-        NULL, &prop_hash,
+        NULL,
+        get_explicit_props ? &prop_hash : NULL,
         get_target_inherited_props ? &inherited_props : NULL,
         target_relative, revnum,
         SVN_DIRENT_KIND, scratch_pool));
@@ -1015,7 +1126,8 @@ remote_proplist(const char *target_prefi
     {
       SVN_ERR(svn_ra_get_file2(
         ra_session, target_relative, revnum,
-        NULL, NULL, &prop_hash,
+        NULL, NULL,
+        get_explicit_props ? &prop_hash : NULL,
         get_target_inherited_props ? &inherited_props : NULL,
         scratch_pool));
     }
@@ -1035,42 +1147,44 @@ remote_proplist(const char *target_prefi
                              _("Server does not support retrieving "
                                "inherited properties"));
 
-  /* Filter out non-regular properties, since the RA layer returns all
-     kinds.  Copy regular properties keys/vals from the prop_hash
-     allocated in SCRATCH_POOL to the "final" hash allocated in POOL. */
-  final_hash = apr_hash_make(result_pool);
-  for (hi = apr_hash_first(scratch_pool, prop_hash);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      apr_ssize_t klen = svn__apr_hash_index_klen(hi);
-      svn_string_t *value = svn__apr_hash_index_val(hi);
-      svn_prop_kind_t prop_kind;
+  if (get_explicit_props)
+    {
+      /* Filter out non-regular properties, since the RA layer returns all
+         kinds.  Copy regular properties keys/vals from the prop_hash
+         allocated in SCRATCH_POOL to the "final" hash allocated in POOL. */
+      final_hash = apr_hash_make(result_pool);
+      for (hi = apr_hash_first(scratch_pool, prop_hash);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          apr_ssize_t klen = svn__apr_hash_index_klen(hi);
+          svn_string_t *value = svn__apr_hash_index_val(hi);
+          svn_prop_kind_t prop_kind;
 
-      prop_kind = svn_property_kind2(name);
+          prop_kind = svn_property_kind2(name);
 
-      if (prop_kind == svn_prop_regular_kind)
-        {
-          name = apr_pstrdup(result_pool, name);
-          value = svn_string_dup(value, result_pool);
-          apr_hash_set(final_hash, name, klen, value);
-        }
+          if (prop_kind == svn_prop_regular_kind)
+            {
+              name = apr_pstrdup(result_pool, name);
+              value = svn_string_dup(value, result_pool);
+              apr_hash_set(final_hash, name, klen, value);
+            }
+        }  
     }
 
-
   if (get_target_inherited_props)
-    {
-      inherited_props = svn_prop_inherited_array_dup(inherited_props,
-                                                     result_pool,
-                                                     scratch_pool);
-    }
+    inherited_props = svn_prop_inherited_array_dup(inherited_props,
+                                                   result_pool,
+                                                   scratch_pool);
+  else
+    inherited_props = NULL;
 
-  SVN_ERR(call_receiver(target_full_url, final_hash,
-                        get_target_inherited_props ? inherited_props : NULL,
+  SVN_ERR(call_receiver(target_full_url, final_hash, inherited_props,
                         receiver, receiver_baton, result_pool));
 
   if (depth > svn_depth_empty
+      && get_explicit_props
       && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0))
     {
       apr_pool_t *subpool = svn_pool_create(scratch_pool);
@@ -1101,6 +1215,7 @@ remote_proplist(const char *target_prefi
                                       this_ent->kind,
                                       revnum,
                                       ra_session,
+                                      TRUE,
                                       FALSE,
                                       depth_below_here,
                                       receiver,
@@ -1170,6 +1285,8 @@ svn_client_proplist4(const char *path_or
                      apr_pool_t *scratch_pool)
 {
   const char *url;
+  svn_boolean_t local_explicit_props;
+  svn_boolean_t local_iprops;
 
   peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
                                                         path_or_url);
@@ -1178,9 +1295,19 @@ svn_client_proplist4(const char *path_or
   if (depth == svn_depth_unknown)
     depth = svn_depth_empty;
 
-  if (! svn_path_is_url(path_or_url)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
+  local_explicit_props =
+    (! svn_path_is_url(path_or_url)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind));
+
+  local_iprops =
+    (local_explicit_props
+     && (peg_revision->kind == svn_opt_revision_working
+         || peg_revision->kind == svn_opt_revision_unspecified )
+     && (revision->kind == svn_opt_revision_working
+         || revision->kind == svn_opt_revision_unspecified ));
+
+  if (local_explicit_props)
     {
       svn_boolean_t pristine;
       svn_node_kind_t kind;
@@ -1206,6 +1333,48 @@ svn_client_proplist4(const char *path_or
                                                           scratch_pool));
         }
 
+      if (get_target_inherited_props && local_iprops)
+        {
+          apr_array_header_t *iprops;
+          svn_boolean_t cached_iprops_found;
+
+          SVN_ERR(svn_wc__get_iprops(&iprops, &cached_iprops_found,
+                                     ctx->wc_ctx, local_abspath,
+                                     NULL, scratch_pool, scratch_pool));
+
+          /* If the cached inherited properties were not found, then ask the
+             repository for them. */
+          if (!cached_iprops_found)
+            {
+              svn_ra_session_t *ra_session;
+              svn_node_kind_t kind;
+              svn_revnum_t revnum;
+              apr_array_header_t *remote_iprops;
+              int i;
+
+              /* Get an RA session for this URL. */
+              SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
+                                                       &url, path_or_url,
+                                                       NULL, peg_revision,
+                                                       revision, ctx,
+                                                       scratch_pool));
+
+              SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind,
+                                        scratch_pool));
+              SVN_ERR(svn_ra_get_inherited_props(ra_session, &remote_iprops,
+                                                 "", revnum, result_pool));
+              for (i = remote_iprops->nelts - 1; i >= 0; i--)
+                {
+                  svn_prop_inherited_item_t *remote_iprop =
+                    APR_ARRAY_IDX(remote_iprops, i, svn_prop_inherited_item_t *);
+                  svn_sort__array_insert(&remote_iprop, iprops, 0);
+                }
+            }
+
+          SVN_ERR(call_receiver(path_or_url, NULL, iprops, receiver,
+                                receiver_baton, scratch_pool));
+        }
+
       if (changelists && changelists->nelts)
         SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash,
                                            changelists, scratch_pool));
@@ -1250,11 +1419,89 @@ svn_client_proplist4(const char *path_or
 
         }
     }
-  else /* remote target */
+  if ((get_target_inherited_props && !local_iprops)
+      || !local_explicit_props)
     {
       svn_ra_session_t *ra_session;
       svn_node_kind_t kind;
       svn_revnum_t revnum;
+      svn_opt_revision_t new_operative_rev;
+      svn_opt_revision_t new_peg_rev;
+
+      /* Peg or operative revisions may be WC specific for
+         PATH_OR_URL's explicit props, but still require us to
+         contact the repository for the inherited properties. */
+      if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)
+          || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+        {
+          svn_revnum_t origin_rev;
+          const char *repos_relpath;
+          const char *repos_root_url;
+          const char *repos_uuid;
+          const char *local_abspath;
+          const char *copy_root_abspath;
+          svn_boolean_t is_copy;
+
+          SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
+                                          scratch_pool));
+
+          if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+            {
+              SVN_ERR(svn_wc__node_get_origin(&is_copy,
+                                              &origin_rev,
+                                              &repos_relpath,
+                                              &repos_root_url,
+                                              &repos_uuid,
+                                              &copy_root_abspath,
+                                              ctx->wc_ctx,
+                                              local_abspath,
+                                              FALSE, /* scan_deleted */
+                                              result_pool,
+                                              scratch_pool));
+              if (repos_relpath)
+                {
+                  path_or_url = svn_path_url_add_component2(repos_root_url,
+                                                            repos_relpath,
+                                                            scratch_pool);
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+                    {
+                      svn_revnum_t resolved_peg_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(&resolved_peg_rev,
+                                                              NULL, ctx->wc_ctx,
+                                                              local_abspath, NULL,
+                                                              peg_revision,
+                                                              scratch_pool));
+                      new_peg_rev.kind = svn_opt_revision_number;
+                      new_peg_rev.value.number = resolved_peg_rev;
+                      peg_revision = &new_peg_rev;
+                    }
+
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+                    {
+                      svn_revnum_t resolved_operative_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(&resolved_operative_rev,
+                                                              NULL, ctx->wc_ctx,
+                                                              local_abspath, NULL,
+                                                              revision,
+                                                              scratch_pool));
+                      new_operative_rev.kind = svn_opt_revision_number;
+                      new_operative_rev.value.number = resolved_operative_rev;
+                      revision = &new_operative_rev;
+                    }
+                }
+              else
+                {
+                  /* PATH_OR_URL doesn't exist in the repository, so there are
+                     obviously not inherited props to be found there. If we
+                     already found the explicit props in the WC then we're
+                     done. */
+                  if (local_explicit_props)
+                    return SVN_NO_ERROR;
+                }
+            }
+        }
 
       /* Get an RA session for this URL. */
       SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
@@ -1265,9 +1512,10 @@ svn_client_proplist4(const char *path_or
       SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, result_pool));
 
       SVN_ERR(remote_proplist(url, "", kind, revnum, ra_session,
-                              get_target_inherited_props, depth,
-                              receiver, receiver_baton, result_pool,
-                              scratch_pool));
+                              !local_explicit_props,
+                              (get_target_inherited_props && !local_iprops),
+                              depth, receiver, receiver_baton,
+                              result_pool, scratch_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/inheritable-props/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/switch.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/switch.c Tue Jun 26 00:55:07 2012
@@ -296,6 +296,10 @@ switch_internal(svn_revnum_t *result_rev
                                            ctx, pool));
     }
 
+  /* Cache inherited props. */
+  SVN_ERR(svn_client__update_inheritable_props(local_abspath, depth,
+                                               ra_session, ctx, pool));
+
   /* Sleep to ensure timestamp integrity (we do this regardless of
      errors in the actual switch operation(s)). */
   if (sleep_here)

Modified: subversion/branches/inheritable-props/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/update.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/update.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/update.c Tue Jun 26 00:55:07 2012
@@ -201,6 +201,7 @@ update_internal(svn_revnum_t *result_rev
   svn_boolean_t sleep_here = FALSE;
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
   svn_boolean_t clean_checkout = FALSE;
+  svn_boolean_t is_not_present;
   const char *diff3_cmd;
   svn_ra_session_t *ra_session;
   const char *preserved_exts_str;
@@ -433,6 +434,22 @@ update_internal(svn_revnum_t *result_rev
                                            ctx, pool));
     }
 
+  /* Cache inherited props. */
+  err = svn_wc__node_is_status_not_present(&is_not_present, ctx->wc_ctx,
+                                           local_abspath, pool);
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+        return svn_error_trace(err);
+
+      svn_error_clear(err);
+      err = SVN_NO_ERROR;
+      is_not_present = TRUE;
+    }
+  if (! is_not_present)
+    SVN_ERR(svn_client__update_inheritable_props(local_abspath, depth,
+                                                 ra_session, ctx, pool));
+
   if (sleep_here)
     svn_io_sleep_for_timestamps(local_abspath, pool);
 

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/props.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/props.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/props.c Tue Jun 26 00:55:07 2012
@@ -46,6 +46,7 @@
 #include "svn_wc.h"
 #include "svn_utf.h"
 #include "svn_diff.h"
+#include "svn_sorts.h"
 
 #include "private/svn_wc_private.h"
 #include "private/svn_mergeinfo_private.h"
@@ -2732,3 +2733,253 @@ svn_wc__has_magic_property(const apr_arr
     }
   return FALSE;
 }
+
+/* Remove all prop name value pairs from PROP_HASH where the property
+   name is not PROPNAME. */
+static void
+filter_unwanted_props(apr_hash_t *prop_hash,
+                      const char * propname,
+                      apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, prop_hash);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *ipropname = svn__apr_hash_index_key(hi);
+
+      if (strcmp(ipropname, propname) != 0)
+        apr_hash_set(prop_hash, ipropname, APR_HASH_KEY_STRING, NULL);
+    }
+  return;
+}
+
+svn_error_t *
+svn_wc__get_iprops(apr_array_header_t **inherited_props,
+                   svn_boolean_t *cached_iprops_found,
+                   svn_wc_context_t *wc_ctx,
+                   const char *local_abspath,
+                   const char *propname,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_array_header_t *cached_iprops = NULL;
+  const char *parent_abspath = local_abspath;
+  svn_boolean_t is_wc_root = FALSE;
+
+  SVN_ERR_ASSERT(inherited_props);
+  *inherited_props = apr_array_make(result_pool, 1,
+                                    sizeof(svn_prop_inherited_item_t *));
+
+  /* Our starting assumption. */
+  *cached_iprops_found = FALSE;
+
+  /* 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)
+    {
+      apr_hash_t *actual_props;
+
+      SVN_ERR(svn_wc_is_wc_root2(&is_wc_root, wc_ctx, parent_abspath,
+                                 scratch_pool));
+      if (is_wc_root)
+        {
+          const char *child_repos_relpath;
+
+          SVN_ERR(svn_wc__node_get_repos_relpath(&child_repos_relpath,
+                                                 wc_ctx, parent_abspath,
+                                                 scratch_pool,
+                                                 scratch_pool));
+
+          /* If the WC root is also the root of the repository then by
+             definition there are no inheritable properties to be had,
+             but we still consider the question "did we definitively find
+             any iprops to be found?" answered in the affirmative. */
+          if (child_repos_relpath[0] == '\0')
+            {
+              *cached_iprops_found = TRUE;
+            }
+          else
+            {
+              /* Grab the cached inherited properties for the WC root. */
+              SVN_ERR(svn_wc__db_read_cached_iprops(&cached_iprops,
+                                                    wc_ctx->db,
+                                                    parent_abspath,
+                                                    scratch_pool,
+                                                    scratch_pool));
+              if (cached_iprops)
+                {
+                  *cached_iprops_found = TRUE;          
+                }          
+            }
+        }
+
+      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
+         LOCAL_ABSPATH can inherit properties from it. */
+      if (strcmp(local_abspath, parent_abspath) != 0)
+        {
+          SVN_ERR(svn_wc__db_read_props(&actual_props, wc_ctx->db,
+                                        parent_abspath, result_pool,
+                                        scratch_pool));
+          if (actual_props)
+            {
+              /* If we only want PROPNAME filter out any other properties. */
+              if (propname)
+                filter_unwanted_props(actual_props, propname, scratch_pool);
+
+              if (apr_hash_count(actual_props))
+                {
+                  svn_prop_inherited_item_t *iprop_elt =
+                    apr_pcalloc(result_pool,
+                                sizeof(svn_prop_inherited_item_t));
+                  iprop_elt->path_or_url = apr_pstrdup(result_pool,
+                                                       parent_abspath);
+                  iprop_elt->prop_hash = actual_props;
+                  /* Build the output array in depth-first order. */
+                  svn_sort__array_insert(&iprop_elt, *inherited_props, 0);
+                }
+            }
+        }
+
+      /* Inheritance only goes as far as the nearest WC root. */
+      if (is_wc_root)
+        break;
+
+      /* Keep looking for the WC root. */
+      parent_abspath = svn_dirent_dirname(parent_abspath, scratch_pool);
+    }
+
+  if (cached_iprops)
+    {
+      for (i = cached_iprops->nelts - 1; i >= 0; i--)
+        {
+          svn_prop_inherited_item_t *cached_iprop =
+            APR_ARRAY_IDX(cached_iprops, i, svn_prop_inherited_item_t *);
+
+          /* An empty property hash in the iprops cache means there are no
+             inherited properties. */
+          if (apr_hash_count(cached_iprop->prop_hash) == 0)
+            continue;
+
+          if (propname)
+            filter_unwanted_props(cached_iprop->prop_hash, propname,
+                                  scratch_pool);
+
+          /* If we didn't filter everything then keep this iprop. */
+          if (apr_hash_count(cached_iprop->prop_hash))
+            svn_sort__array_insert(&cached_iprop, *inherited_props, 0);
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__cache_iprops(apr_array_header_t *inherited_props,
+                     svn_wc_context_t *wc_ctx,
+                     const char *local_abspath,
+                     apr_pool_t *scratch_pool)
+{
+  if (inherited_props)
+    {
+      int i;
+      const char *repos_root_url;
+      svn_revnum_t revision;
+      svn_error_t *err = svn_wc__node_get_base(&revision, NULL,
+                                               &repos_root_url, NULL,
+                                               wc_ctx, local_abspath,
+                                               scratch_pool, scratch_pool);
+
+      /* Can't cache iprops for paths which aren't part of the WC. */
+      if (err)
+        {
+          if (err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
+            {
+              svn_error_clear(err);
+
+              /* Keep error for consistent with the other of the svn_wc__*
+                 private APIs. */
+              return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                                       _("The node '%s' was not found."),
+                                       svn_dirent_local_style(local_abspath,
+                                                              scratch_pool));
+            }
+          else
+            {
+              return svn_error_trace(err);
+            }
+        }
+
+      /* If there is no base node at LOCAL_ABSPATH there is nothing to do. */
+      if (SVN_IS_VALID_REVNUM(revision))
+        {
+          /* Remove stale cached iprops. */
+          SVN_ERR(svn_wc__db_remove_cached_iprops(wc_ctx->db, local_abspath,
+                                                  scratch_pool));
+
+          if (inherited_props->nelts)
+            {
+              for (i = 0; i < inherited_props->nelts; i++)
+                {
+                  svn_prop_inherited_item_t *iprop =
+                    APR_ARRAY_IDX(inherited_props, i,
+                                  svn_prop_inherited_item_t *);
+
+                  /* Only cache properties inherited from the repository. */
+                  if (svn_path_is_url(iprop->path_or_url))
+                    {
+                      const char *repos_parent_relpath =
+                        svn_uri_skip_ancestor(repos_root_url,
+                                              iprop->path_or_url,
+                                              scratch_pool);
+                      SVN_ERR(svn_wc__db_cache_iprops(repos_parent_relpath,
+                                                      iprop->prop_hash,
+                                                      revision, wc_ctx->db,
+                                                      local_abspath,
+                                                      scratch_pool));
+                    }
+                }
+            }
+          else
+            {
+              /* Cache no inheritable props. */
+              SVN_ERR(svn_wc__db_cache_iprops("",
+                                              apr_hash_make(scratch_pool),
+                                              revision,
+                                              wc_ctx->db, local_abspath,
+                                              scratch_pool));
+            }
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__delete_iprops(svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc__db_remove_cached_iprops(wc_ctx->db, local_abspath,
+                                          scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__get_cached_iprop_children(apr_hash_t **iprop_paths,
+                                  svn_depth_t depth,
+                                  svn_wc_context_t *wc_ctx,
+                                  const char *local_abspath,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc__db_get_children_with_cached_iprops(iprop_paths,
+                                                     depth,
+                                                     local_abspath,
+                                                     wc_ctx->db,
+                                                     result_pool,
+                                                     scratch_pool));
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c Tue Jun 26 00:55:07 2012
@@ -5341,7 +5341,7 @@ svn_wc_is_wc_root2(svn_boolean_t *wc_roo
       return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, err, err->message);
     }
 
-  *wc_root = is_root || (kind == svn_kind_dir && is_switched);
+  *wc_root = is_root || is_switched;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/wc-metadata.sql?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/wc-metadata.sql Tue Jun 26 00:55:07 2012
@@ -573,6 +573,44 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED 
                                                       def_local_relpath,
                                                       local_relpath);
 
+/* ------------------------------------------------------------------------- */
+
+/* The INHERITABLE_PROPS table describes the properties inherited by any
+   base nodes in the WC which are WC roots (considering switched subtrees
+   as WC roots). 
+
+   Zero or more INHERITABLE_PROPS table rows exist for a given WC root
+   node in the NODES table, one for each repository parent the node
+   inherits from.  If the WC root is also the root of the repository
+   then no row exists.
+ */
+
+-- STMT_INHERITABLE_PROPS
+
+CREATE TABLE INHERITABLE_PROPS (
+  wc_id  INTEGER NOT NULL,
+  local_relpath  TEXT NOT NULL,
+
+  /* ### IPROPS: Will we ever need OP_DEPTH? We are only caching properties
+                 base nodes which have a corresponding repository location,
+                 so OP_DEPTH should always be 0. */
+  op_depth  INTEGER NOT NULL,
+
+  /* The repository parent and revision from which the node inherits. */
+  repos_parent_relpath  TEXT NOT NULL,
+  revision  INTEGER,
+
+  /* Serialized skel of this node's inherited properties from
+     REPOS_PARENT_RELPATH.  May be empty if the node inherits no
+     properties from any repository parent. */
+  inheritable_props  BLOB,
+
+  PRIMARY KEY (wc_id, local_relpath, op_depth, repos_parent_relpath),
+  FOREIGN KEY(wc_id, local_relpath, op_depth) REFERENCES NODES (wc_id,
+                                                                local_relpath,
+                                                                op_depth)
+  );
+
 /* Format 20 introduces NODES and removes BASE_NODE and WORKING_NODE */
 
 -- STMT_UPGRADE_TO_20

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/wc-queries.sql?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/wc-queries.sql Tue Jun 26 00:55:07 2012
@@ -1444,6 +1444,48 @@ WHERE wc_id == ?1
 
 /* ------------------------------------------------------------------------- */
 
+/* Queries for cached inherited properties. */
+
+-- STMT_SELECT_IPROPS
+SELECT repos_parent_relpath, inheritable_props FROM inheritable_props
+WHERE wc_id = ?1
+  AND local_relpath = ?2
+  AND op_depth = ?3
+  AND revision = ?4
+ORDER BY repos_parent_relpath
+
+-- STMT_INSERT_IPROP
+INSERT OR REPLACE INTO inheritable_props (
+  wc_id, local_relpath, op_depth, repos_parent_relpath, revision,
+  inheritable_props)
+VALUES (?1, ?2, ?3, ?4, ?5, ?6)
+
+-- STMT_DELETE_IPROPS_RECURSIVE
+DELETE FROM inheritable_props
+WHERE wc_id = ?1
+  AND (?2 = ''
+       OR local_relpath = ?2
+       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+
+-- STMT_DELETE_IPROPS
+DELETE FROM inheritable_props
+WHERE wc_id = ?1
+  AND (local_relpath = ?2)
+
+-- STMT_SELECT_INODES
+SELECT local_relpath FROM inheritable_props
+WHERE wc_id = ?1
+  AND local_relpath = ?2
+
+-- STMT_SELECT_INODES_RECURSIVE
+SELECT local_relpath FROM inheritable_props
+WHERE wc_id = ?1
+  AND (?2 = ''
+       OR local_relpath = ?2
+       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+
+/* ------------------------------------------------------------------------- */
+
 /* Grab all the statements related to the schema.  */
 
 -- include: wc-metadata

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.c?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.c Tue Jun 26 00:55:07 2012
@@ -1442,6 +1442,7 @@ create_db(svn_sqlite__db_t **sdb,
   SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_NODES));
   SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_NODES_TRIGGERS));
   SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_EXTERNALS));
+  SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_INHERITABLE_PROPS));
 
   /* Insert the repository. */
   SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid, *sdb,
@@ -1966,6 +1967,12 @@ db_base_remove(void *baton,
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
+  /* Remove any cached inherited properties for LOCAL_RELPATH. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_DELETE_IPROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_DELETE_BASE_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
@@ -6064,6 +6071,13 @@ remove_node_txn(void *baton,
                           wcroot, local_relpath,
                           scratch_pool, scratch_pool));
 
+  /* Remove all cached inherited properties for LOCAL_RELPATH. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_DELETE_IPROPS_RECURSIVE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                            wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_DELETE_NODES_RECURSIVE));
 
@@ -8414,6 +8428,231 @@ svn_wc__db_read_pristine_props(apr_hash_
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_read_cached_iprops(apr_array_header_t **iprops,
+                              svn_wc__db_t *db,
+                              const char *local_abspath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  const char *repos_root_url;
+  svn_revnum_t revision;
+  apr_int64_t op_depth;
+  const char *repos_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_read_info(NULL, NULL,
+                               &revision, &repos_relpath, &repos_root_url,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, db, local_abspath, result_pool,
+                               scratch_pool));
+
+  if (repos_relpath && repos_relpath[0] == '\0')
+    {
+      /* LOCAL_ABSPATH reflects the root of the repository, so there is
+         no parents to inherit from. */
+      *iprops = apr_array_make(result_pool, 0,
+                               sizeof(svn_prop_inherited_item_t *));
+    }
+  else
+    {
+      SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                    db, local_abspath,
+                                                    scratch_pool,
+                                                    scratch_pool));
+      VERIFY_USABLE_WCROOT(wcroot);
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_IPROPS));
+      SVN_ERR(op_depth_of(&op_depth, wcroot, local_relpath));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isir", wcroot->wc_id, local_relpath,
+                                op_depth, revision));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      if (!have_row)
+        {
+          /* No cached iprops. */
+          *iprops = NULL;
+        }
+      else
+        {
+          *iprops = apr_array_make(result_pool, 1,
+                                   sizeof(svn_prop_inherited_item_t *));
+          while (have_row)
+            {
+              const char *repos_parent_relpath;
+              apr_hash_t *inherited_props;
+              svn_prop_inherited_item_t *new_iprop =
+                apr_palloc(result_pool, sizeof(*new_iprop));
+
+              repos_parent_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+              SVN_ERR(svn_sqlite__column_properties(&inherited_props, stmt, 1,
+                                                    result_pool,
+                                                    scratch_pool));
+              new_iprop->path_or_url = svn_path_url_add_component2(
+                 repos_root_url, repos_parent_relpath, result_pool);
+              new_iprop->prop_hash = inherited_props;
+              APR_ARRAY_PUSH(*iprops, svn_prop_inherited_item_t *) =
+                new_iprop;
+              SVN_ERR(svn_sqlite__step(&have_row, stmt));
+            }
+        }
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Recursive body of svn_wc__db_get_children_with_cached_iprops. */
+svn_error_t *
+get_children_with_cached_iprops(apr_hash_t *iprop_paths,
+                                svn_depth_t depth,
+                                const char *local_abspath,
+                                svn_wc__db_t *db,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                                                local_abspath, scratch_pool,
+                                                scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+  if (depth == svn_depth_empty
+      || depth == svn_depth_files
+      || depth == svn_depth_immediates)
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_INODES));  
+    }
+  else /* Default to svn_depth_infinity. */
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_INODES_RECURSIVE));  
+    }
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  while (have_row)
+    {
+      const char *relpath_with_cache = svn_sqlite__column_text(stmt, 0,
+                                                               NULL);
+      const char *abspath_with_cache = svn_dirent_join(wcroot->abspath,
+                                                       relpath_with_cache,
+                                                       result_pool);
+      apr_hash_set(iprop_paths, abspath_with_cache, APR_HASH_KEY_STRING,
+                   abspath_with_cache);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (depth == svn_depth_files || depth == svn_depth_immediates)
+    {
+      const apr_array_header_t *rel_children;
+      int i;
+
+      SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
+                                                       db, local_abspath,
+                                                       scratch_pool,
+                                                       scratch_pool));
+      for (i = 0; i < rel_children->nelts; i++)
+        {
+          const char *child_abspath = svn_dirent_join(
+            local_abspath, APR_ARRAY_IDX(rel_children, i, const char *),
+            scratch_pool);
+
+          if (depth == svn_depth_files)
+            {
+              svn_kind_t child_kind;
+
+              SVN_ERR(svn_wc__db_read_kind(&child_kind, db, child_abspath,
+                                           FALSE, scratch_pool));
+              if (child_kind != svn_kind_file)
+                continue;
+            }
+
+          SVN_ERR(get_children_with_cached_iprops(iprop_paths,
+                                                  svn_depth_empty,
+                                                  child_abspath, db,
+                                                  result_pool,
+                                                  scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_get_children_with_cached_iprops(apr_hash_t **iprop_paths,
+                                           svn_depth_t depth,
+                                           const char *local_abspath,
+                                           svn_wc__db_t *db,
+                                           apr_pool_t *result_pool,
+                                           apr_pool_t *scratch_pool)
+{
+  *iprop_paths = apr_hash_make(result_pool);
+  SVN_ERR(get_children_with_cached_iprops(*iprop_paths, depth,
+                                          local_abspath, db, result_pool,
+                                          scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_cache_iprops(const char *repos_parent_relpath,
+                        apr_hash_t *props,
+                        svn_revnum_t revision,
+                        svn_wc__db_t *db,
+                        const char *local_abspath,
+                        apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  svn_sqlite__stmt_t *stmt;
+  const char *local_relpath;
+  apr_int64_t op_depth;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
+  SVN_ERR(op_depth_of(&op_depth, wcroot, local_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_IPROP));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isisr", wcroot->wc_id, local_relpath,
+                            op_depth, repos_parent_relpath, revision));
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 6, props, scratch_pool));
+  return svn_error_trace(svn_sqlite__step_done(stmt));
+}
+
+svn_error_t *
+svn_wc__db_remove_cached_iprops(svn_wc__db_t *db,
+                                const char *local_abspath,
+                                apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  svn_sqlite__stmt_t *stmt;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_IPROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  return svn_error_trace(svn_sqlite__step_done(stmt));  
+}
 
 svn_error_t *
 svn_wc__db_read_children_of_working_node(const apr_array_header_t **children,

Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.h?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/wc_db.h Tue Jun 26 00:55:07 2012
@@ -2062,6 +2062,64 @@ svn_wc__db_read_pristine_props(apr_hash_
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
+/* Read a BASE node's inherited property information.
+
+   Set *IPROPS to to a depth-first ordered array of
+   svn_prop_inherited_item_t * structures representing the cached
+   inherited properties for the BASE node at LOCAL_ABSPATH.
+
+   If no cached properties are found, then set *IPROPS to NULL.
+   If LOCAL_ABSPATH represents the root of the repository, then set
+   *IPROPS to an empty array.
+
+   Allocate *IPROPS in RESULT_POOL, use SCRATCH_POOL for temporary
+   allocations. */
+svn_error_t *
+svn_wc__db_read_cached_iprops(apr_array_header_t **iprops,
+                              svn_wc__db_t *db,
+                              const char *local_abspath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
+
+/* Find BASE nodes with cached inherited properties.
+
+   Set *IPROPS_PATHS to a hash mapping const char * absolute working copy
+   paths to the same for each path in the working copy at or below
+   LOCAL_ABSPATH, limited by DEPTH, that has cached inherited properties
+   for the BASE node of the path.  Allocate *IPROP_PATHS in RESULT_POOL.
+   Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_wc__db_get_children_with_cached_iprops(apr_hash_t **iprop_paths,
+                                           svn_depth_t depth,
+                                           const char *local_abspath,
+                                           svn_wc__db_t *db,
+                                           apr_pool_t *result_pool,
+                                           apr_pool_t *scratch_pool);
+
+/* Cache inherited properites for a node in the BASE tree.
+
+   Cache the inherited properties PROPS (a hash table mapping char *
+   property names onto svn_string_t * property values) inherited from
+   REPOS_PARENT_RELPATH at REVISION, for the BASE node at LOCAL_ABSPATH.
+
+   Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_wc__db_cache_iprops(const char *repos_parent_relpath,
+                        apr_hash_t *props,
+                        svn_revnum_t revision,
+                        svn_wc__db_t *db,
+                        const char *local_abspath,
+                        apr_pool_t *scratch_pool);
+
+/* Delete a BASE node's inherited properites.
+
+   Remove any inherited property caches for the BASE node at
+   LOCAL_ABSPATH.  Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_wc__db_remove_cached_iprops(svn_wc__db_t *db,
+                                const char *local_abspath,
+                                apr_pool_t *scratch_pool);
+
 /* Set *CHILDREN to a new array of the (const char *) basenames of the
    immediate children of the working node at LOCAL_ABSPATH in DB.
 

Modified: subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py?rev=1353788&r1=1353787&r2=1353788&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py Tue Jun 26 00:55:07 2012
@@ -5786,14 +5786,14 @@ def merge_to_path_with_switched_children
   expected_mergeinfo_output = wc.State(A_COPY_D_path, {
     ''      : Item(status=' G'),
     'H'     : Item(status=' G'),
-    'H/psi' : Item(status=' G')
+    'H/psi' : Item(status=' U')
     })
   expected_elision_output = wc.State(A_COPY_D_path, {
     })
   expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
   expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
   expected_disk_D.tweak('H/psi', contents="New content",
-                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
+                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
   expected_status_D.tweak('H/psi', status='MM')
   svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
                                        sbox.repo_url + '/A/D', None,
@@ -5856,7 +5856,7 @@ def merge_to_path_with_switched_children
     'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
     'D/H/chi'   : Item("This is the file 'chi'.\n"),
     'D/H/psi'   : Item("New content",
-                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_COPY_path, { })