You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/02/14 12:10:26 UTC
svn commit: r1446118 - /subversion/trunk/subversion/libsvn_repos/rev_hunt.c
Author: rhuijben
Date: Thu Feb 14 11:10:25 2013
New Revision: 1446118
URL: http://svn.apache.org/r1446118
Log:
Optimize the code path for obtaining revisions backwards for the blame
algorithm. And while there reduce the memory footprint of the ordinary
revision obtaining a tiny bit by introducing a scratch pool.
Suggested by: jcorvel
I can't reproduce it on repositories that I have access to, but he
explains that he sees a long delay before the first revision is
transferred. This patch should take care of that for the reversed
operation.
* subversion/libsvn_repos/rev_hunt.c
(check_ancestry_of_peg_path): Initialize variable to NULL to shut up
compiler warning.
(find_merged_revisions): Split passed pool in result and scratch pool, to
allow clearing intermediate information earlier.
(get_file_revs_backwards): New function.
(svn_repos_get_file_revs2): Rename pool to scratch_pool. Delegate reverse
handling to get_file_revs_backwards. Use iterpools as scratch pools for
version calculation.
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=1446118&r1=1446117&r2=1446118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/trunk/subversion/libsvn_repos/rev_hunt.c Thu Feb 14 11:10:25 2013
@@ -532,7 +532,7 @@ check_ancestry_of_peg_path(svn_boolean_t
{
svn_fs_root_t *root;
svn_fs_history_t *history;
- const char *path;
+ const char *path = NULL;
svn_revnum_t revision;
apr_pool_t *lastpool, *currpool;
@@ -1252,17 +1252,18 @@ find_merged_revisions(apr_array_header_t
apr_hash_t *duplicate_path_revs,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const apr_array_header_t *old;
apr_array_header_t *new_merged_path_revs;
apr_pool_t *iterpool, *last_pool;
apr_array_header_t *merged_path_revisions =
- apr_array_make(pool, 0, sizeof(struct path_revision *));
+ apr_array_make(scratch_pool, 0, sizeof(struct path_revision *));
old = mainline_path_revisions;
- iterpool = svn_pool_create(pool);
- last_pool = svn_pool_create(pool);
+ iterpool = svn_pool_create(scratch_pool);
+ last_pool = svn_pool_create(scratch_pool);
do
{
@@ -1325,8 +1326,8 @@ find_merged_revisions(apr_array_header_t
TRUE, TRUE,
duplicate_path_revs,
authz_read_func,
- authz_read_baton, pool,
- iterpool3));
+ authz_read_baton,
+ result_pool, iterpool3));
}
svn_pool_destroy(iterpool3);
}
@@ -1350,7 +1351,8 @@ find_merged_revisions(apr_array_header_t
sizeof(struct path_revision *), compare_path_revisions);
/* Copy to the output array. */
- *merged_path_revisions_out = apr_array_copy(pool, merged_path_revisions);
+ *merged_path_revisions_out = apr_array_copy(result_pool,
+ merged_path_revisions);
svn_pool_destroy(iterpool);
svn_pool_destroy(last_pool);
@@ -1447,6 +1449,114 @@ send_path_revision(struct path_revision
return SVN_NO_ERROR;
}
+/* Similar to svn_repos_get_file_revs2() but returns paths while walking
+ history instead of after collecting all history.
+
+ This allows implementing clients to immediately start processing and
+ stop when they got the information they need. (E.g. all or a specific set
+ of lines were modified) */
+static svn_error_t *
+get_file_revs_backwards(svn_repos_t *repos,
+ const char *path,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ svn_file_rev_handler_t handler,
+ void *handler_baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool, *last_pool;
+ svn_fs_history_t *history;
+ svn_fs_root_t *root;
+ svn_node_kind_t kind;
+ struct send_baton sb;
+
+ /* We switch between two pools while looping and so does the path-rev
+ handler for actually reported revisions. We do this as we
+ need just information from last iteration to be available. */
+
+ iterpool = svn_pool_create(scratch_pool);
+ last_pool = svn_pool_create(scratch_pool);
+ sb.iterpool = svn_pool_create(scratch_pool);
+ sb.last_pool = svn_pool_create(scratch_pool);
+
+ /* We want the first txdelta to be against the empty file. */
+ sb.last_root = NULL;
+ sb.last_path = NULL;
+
+ /* Create an empty hash table for the first property diff. */
+ sb.last_props = apr_hash_make(sb.last_pool);
+
+ /* The path had better be a file in this revision. */
+ SVN_ERR(svn_fs_revision_root(&root, repos->fs, end, scratch_pool));
+ SVN_ERR(svn_fs_check_path(&kind, root, path, scratch_pool));
+ if (kind != svn_node_file)
+ return svn_error_createf(SVN_ERR_FS_NOT_FILE,
+ NULL, _("'%s' is not a file in revision %ld"),
+ path, end);
+
+ /* Open a history object. */
+ SVN_ERR(svn_fs_node_history(&history, root, path, scratch_pool));
+ while (1)
+ {
+ struct path_revision *path_rev;
+ svn_revnum_t tmp_revnum;
+ const char *tmp_path;
+
+ svn_pool_clear(iterpool);
+
+ /* Fetch the history object to walk through. */
+ SVN_ERR(svn_fs_history_prev(&history, history, TRUE, iterpool));
+ if (!history)
+ break;
+ SVN_ERR(svn_fs_history_location(&tmp_path, &tmp_revnum,
+ history, iterpool));
+
+ /* Check authorization. */
+ if (authz_read_func)
+ {
+ svn_boolean_t readable;
+ svn_fs_root_t *tmp_root;
+
+ SVN_ERR(svn_fs_revision_root(&tmp_root, repos->fs, tmp_revnum,
+ iterpool));
+ SVN_ERR(authz_read_func(&readable, tmp_root, tmp_path,
+ authz_read_baton, iterpool));
+ if (! readable)
+ break;
+ }
+
+ /* We didn't break, so we must really want this path-rev. */
+ path_rev = apr_palloc(iterpool, sizeof(*path_rev));
+ path_rev->path = tmp_path;
+ path_rev->revnum = tmp_revnum;
+ path_rev->merged = FALSE;
+
+ SVN_ERR(send_path_revision(path_rev, repos, &sb,
+ handler, handler_baton));
+
+ if (path_rev->revnum <= start)
+ break;
+
+ /* Swap pools. */
+ {
+ apr_pool_t *tmp_pool = iterpool;
+ iterpool = last_pool;
+ last_pool = tmp_pool;
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+ svn_pool_destroy(last_pool);
+ svn_pool_destroy(sb.last_pool);
+ svn_pool_destroy(sb.iterpool);
+
+ return SVN_NO_ERROR;
+
+}
+
+
/* We don't yet support sending revisions in reverse order; the caller wait
* until we've traced back through the entire history, and then accept
* them from oldest to youngest. Someday this may change, but in the meantime,
@@ -1466,7 +1576,7 @@ send_path_revision(struct path_revision
*
* 2013-02: Added a very simple reverse for mainline only changes. Before this,
* this would return an error (path not found) or just the first
- * revision.
+ * revision before end.
*/
svn_error_t *
svn_repos_get_file_revs2(svn_repos_t *repos,
@@ -1478,66 +1588,65 @@ svn_repos_get_file_revs2(svn_repos_t *re
void *authz_read_baton,
svn_file_rev_handler_t handler,
void *handler_baton,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
apr_array_header_t *mainline_path_revisions, *merged_path_revisions;
apr_hash_t *duplicate_path_revs;
struct send_baton sb;
int mainline_pos, merged_pos;
- svn_boolean_t reverse = FALSE;
if (end < start)
{
- svn_revnum_t tmp;
-
- /* Reporting merged revision backwards makes no sense */
if (include_merged_revisions)
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
- tmp = end;
- end = start;
- start = tmp;
- reverse = TRUE;
+ return svn_error_trace(
+ get_file_revs_backwards(repos, path,
+ end, start,
+ authz_read_func,
+ authz_read_baton,
+ handler,
+ handler_baton,
+ scratch_pool));
}
+ /* We switch between two pools while looping, since we need information from
+ the last iteration to be available. */
+ sb.iterpool = svn_pool_create(scratch_pool);
+ sb.last_pool = svn_pool_create(scratch_pool);
+
+ /* We want the first txdelta to be against the empty file. */
+ sb.last_root = NULL;
+ sb.last_path = NULL;
+
+ /* Create an empty hash table for the first property diff. */
+ sb.last_props = apr_hash_make(sb.last_pool);
+
+
/* Get the revisions we are interested in. */
- duplicate_path_revs = apr_hash_make(pool);
- mainline_path_revisions = apr_array_make(pool, 0,
+ duplicate_path_revs = apr_hash_make(scratch_pool);
+ mainline_path_revisions = apr_array_make(scratch_pool, 100,
sizeof(struct path_revision *));
SVN_ERR(find_interesting_revisions(mainline_path_revisions, repos, path,
start, end, include_merged_revisions,
FALSE, duplicate_path_revs,
- authz_read_func, authz_read_baton, pool,
- pool));
+ authz_read_func, authz_read_baton,
+ scratch_pool, sb.iterpool));
/* If we are including merged revisions, go get those, too. */
if (include_merged_revisions)
SVN_ERR(find_merged_revisions(&merged_path_revisions, start,
mainline_path_revisions, repos,
duplicate_path_revs, authz_read_func,
- authz_read_baton, pool));
+ authz_read_baton,
+ scratch_pool, sb.iterpool));
else
- merged_path_revisions = apr_array_make(pool, 0,
+ merged_path_revisions = apr_array_make(scratch_pool, 0,
sizeof(struct path_revision *));
/* We must have at least one revision to get. */
SVN_ERR_ASSERT(mainline_path_revisions->nelts > 0);
- /* We switch betwwen two pools while looping, since we need information from
- the last iteration to be available. */
- sb.iterpool = svn_pool_create(pool);
- sb.last_pool = svn_pool_create(pool);
-
- /* We want the first txdelta to be against the empty file. */
- sb.last_root = NULL;
- sb.last_path = NULL;
-
- if (reverse)
- svn_sort__array_reverse(mainline_path_revisions, pool);
-
- /* Create an empty hash table for the first property diff. */
- sb.last_props = apr_hash_make(sb.last_pool);
-
/* Walk through both mainline and merged revisions, and send them in
reverse chronological order, interleaving as appropriate. */
mainline_pos = mainline_path_revisions->nelts - 1;