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,
+ ©_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,
+ ©_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, { })