Author: philip
Date: Mon Apr 18 18:38:58 2011
New Revision: 1094692
URL: http://svn.apache.org/viewvc?rev=1094692&view=rev
Log:
Make "blame -g" more efficient on the server when svn:mergeinfo is
large.
* subversion/libsvn_repos/rev_hunt.c
(get_merged_mergeinfo): Use the FS path_changed API to check
for property changes before doing expensive svn:mergeinfo
manipulations, don't treat newly created paths as a merge,
avoid allocating some empty hashes.
Modified:
subversion/trunk/subversion/libsvn_repos/rev_hunt.c
Modified: subversion/trunk/subversion/libsvn_repos/rev_hunt.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/rev_hunt.c?rev=1094692&r1=1094691&r2=1094692&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/trunk/subversion/libsvn_repos/rev_hunt.c Mon Apr 18 18:38:58 2011
@@ -1035,7 +1035,8 @@ struct path_revision
};
/* Check for merges in OLD_PATH_REV->PATH at OLD_PATH_REV->REVNUM. Store
- the mergeinfo difference in MERGED_MERGEINFO, allocated in POOL. */
+ the mergeinfo difference in *MERGED_MERGEINFO, allocated in POOL. The
+ returned *MERGED_MERGEINFO will be NULL if there are no changes. */
static svn_error_t *
get_merged_mergeinfo(apr_hash_t **merged_mergeinfo,
svn_repos_t *repos,
@@ -1045,6 +1046,30 @@ get_merged_mergeinfo(apr_hash_t **merged
apr_pool_t *subpool = svn_pool_create(pool);
apr_hash_t *curr_mergeinfo, *prev_mergeinfo, *deleted, *changed;
svn_error_t *err;
+ svn_fs_root_t *root;
+ apr_hash_t *changed_paths;
+ const char *path = old_path_rev->path;
+
+ /* Getting/parsing/diffing svn:mergeinfo is expensive, so only do it
+ if there is a property change. */
+ SVN_ERR(svn_fs_revision_root(&root, repos->fs, old_path_rev->revnum,
+ subpool));
+ SVN_ERR(svn_fs_paths_changed2(&changed_paths, root, subpool));
+ while (1)
+ {
+ svn_fs_path_change2_t *changed_path = apr_hash_get(changed_paths,
+ path,
+ APR_HASH_KEY_STRING);
+ if (changed_path && changed_path->prop_mod)
+ break;
+ if (svn_dirent_is_root(path, strlen(path)))
+ {
+ svn_pool_destroy(subpool);
+ *merged_mergeinfo = NULL;
+ return SVN_NO_ERROR;
+ }
+ path = svn_path_dirname(path, subpool);
+ }
/* First, find the mergeinfo difference for old_path_rev->revnum, and
old_path_rev->revnum - 1. */
@@ -1054,10 +1079,12 @@ get_merged_mergeinfo(apr_hash_t **merged
old_path_rev->revnum - 1, subpool);
if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
{
- /* If the path doesn't exist in the previous revision, assume empty
- mergeinfo. */
+ /* If the path doesn't exist in the previous revision, assume no
+ merges */
svn_error_clear(err);
- prev_mergeinfo = apr_hash_make(subpool);
+ svn_pool_destroy(subpool);
+ *merged_mergeinfo = NULL;
+ return SVN_NO_ERROR;
}
else
SVN_ERR(err);
@@ -1065,10 +1092,14 @@ get_merged_mergeinfo(apr_hash_t **merged
/* Then calculate and merge the differences. */
SVN_ERR(svn_mergeinfo_diff(&deleted, &changed, prev_mergeinfo,
curr_mergeinfo,
FALSE, subpool));
- SVN_ERR(svn_mergeinfo_merge(changed, deleted, subpool));
+ if (apr_hash_count(deleted))
+ SVN_ERR(svn_mergeinfo_merge(changed, deleted, subpool));
/* Store the result. */
- *merged_mergeinfo = svn_mergeinfo_dup(changed, pool);
+ if (apr_hash_count(changed))
+ *merged_mergeinfo = svn_mergeinfo_dup(changed, pool);
+ else
+ *merged_mergeinfo = NULL;
svn_pool_destroy(subpool);