You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/24 12:21:00 UTC
svn commit: r1535330 - in /subversion/trunk: subversion/include/
subversion/libsvn_fs/ subversion/libsvn_repos/ subversion/mod_dav_svn/
tools/server-side/
Author: stefan2
Date: Thu Oct 24 10:21:00 2013
New Revision: 1535330
URL: http://svn.apache.org/r1535330
Log:
Make --auto-moves option affective on legacy repositories (BDB) as well.
Since these don't return copy-from information, we can't do match the
DEL / ADD matching directly in libsvn_fs.
Instead, we move the functionality one level up to libsvn_repos. The
logic is the same despite using yet another path change type. Revert
to v1.6 FS API and update callers.
* subversion/include/svn_fs.h
(svn_fs_paths_changed3): dropp
(svn_fs_paths_changed2): re-instantiate as "current"
* subversion/libsvn_fs/fs-loader.c
(is_deletion,
turn_moves_into_copies,
turn_unique_copies_into_moves): remove here
(svn_fs_paths_changed3): drop
(svn_fs_paths_changed2): call vtable entry directly again
(svn_fs_paths_changed): update
* subversion/libsvn_repos/log.c
(svn_repos_check_revision_access): revert FS API caller
(is_deletion,
turn_moves_into_copies,
turn_unique_copies_into_moves): moved here; use repos layer change type
(detect_changed): revert FS API caller; call move conversion functions here
(fs_mergeinfo_changed,
get_combined_mergeinfo_changes): drop move_behavior parameter again
(do_logs): update caller
* subversion/mod_dav_svn/merge.c
(do_resources): drop move_behavior parameter again
(dav_svn__merge_response): update caller
* tools/server-side/svn-populate-node-origins-index.c
(index_revision_adds): revert FS API caller
* tools/server-side/svn-rep-sharing-stats.c
(process_one_revision): ditto
Modified:
subversion/trunk/subversion/include/svn_fs.h
subversion/trunk/subversion/libsvn_fs/fs-loader.c
subversion/trunk/subversion/libsvn_repos/log.c
subversion/trunk/subversion/mod_dav_svn/merge.c
subversion/trunk/tools/server-side/svn-populate-node-origins-index.c
subversion/trunk/tools/server-side/svn-rep-sharing-stats.c
Modified: subversion/trunk/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_fs.h?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_fs.h (original)
+++ subversion/trunk/subversion/include/svn_fs.h Thu Oct 24 10:21:00 2013
@@ -1399,8 +1399,6 @@ svn_fs_path_change2_create(const svn_fs_
* Allocate and return a hash @a *changed_paths2_p containing descriptions
* of the paths changed under @a root. The hash is keyed with
* <tt>const char *</tt> paths, and has #svn_fs_path_change2_t * values.
- * @a move_behavior determines how moves are being detected and reported;
- * see #svn_fs_move_behavior_t for the various options.
*
* Callers can assume that this function takes time proportional to
* the amount of data output, and does not need to do tree crawls;
@@ -1410,22 +1408,8 @@ svn_fs_path_change2_create(const svn_fs_
*
* Use @a pool for all allocations, including the hash and its values.
*
- * @since New in 1.9.
- */
-svn_error_t *
-svn_fs_paths_changed3(apr_hash_t **changed_paths2_p,
- svn_fs_root_t *root,
- svn_move_behavior_t move_behavior,
- apr_pool_t *pool);
-
-
-/** Same as svn_fs_paths_changed3 but with @a move_behavior set to
- * #svn_fs_move_behavior_no_moves.
- *
- * @deprecated Provided for backward compatibility with the 1.8 API.
* @since New in 1.6.
*/
-SVN_DEPRECATED
svn_error_t *
svn_fs_paths_changed2(apr_hash_t **changed_paths2_p,
svn_fs_root_t *root,
Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.c?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.c Thu Oct 24 10:21:00 2013
@@ -989,177 +989,12 @@ svn_fs_revision_root_revision(svn_fs_roo
return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
}
-/* Return TRUE, if CHANGE deleted the node previously found at its target
- path. */
-static svn_boolean_t
-is_deletion(svn_fs_path_change2_t *change)
-{
- return change->change_kind == svn_fs_path_change_movereplace
- || change->change_kind == svn_fs_path_change_replace
- || change->change_kind == svn_fs_path_change_delete;
-}
-
-/* Change all moves in CHANGES to ADD. Use POOL for temporary allocations.
- */
-static void
-turn_moves_into_copies(apr_hash_t *changes,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
- for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
- {
- const char *key;
- apr_ssize_t klen;
- svn_fs_path_change2_t *change;
- apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
-
- switch (change->change_kind)
- {
- case svn_fs_path_change_move:
- change->change_kind = svn_fs_path_change_add;
- break;
-
- case svn_fs_path_change_movereplace:
- change->change_kind = svn_fs_path_change_replace;
- break;
-
- default:
- break;
- }
- }
-}
-
-/* Replace ADDs with MOVes, if they are unique, have a matching deletion
- * and if the copy-from revision is REVISION-1. Use POOL for temporary
- * allocations.
- */
-static void
-turn_unique_copies_into_moves(apr_hash_t *changes,
- svn_revnum_t revision,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
- apr_hash_t *unique_copy_sources;
- const char **sources;
- int i;
-
- /* find all copy-from paths (ADD and MOV alike) */
-
- svn_boolean_t any_deletion = FALSE;
- apr_array_header_t *copy_sources
- = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
-
- for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
- {
- svn_fs_path_change2_t *change;
- apr_hash_this(hi, NULL, NULL, (void**)&change);
-
- if (change->copyfrom_path && change->copyfrom_rev == revision-1)
- APR_ARRAY_PUSH(copy_sources, const char *)
- = change->copyfrom_path;
-
- any_deletion |= is_deletion(change);
- }
-
- /* no suitable copy-from or no deletion -> no moves */
-
- if (!copy_sources->nelts || !any_deletion)
- return;
-
- /* identify copy-from paths that have been mentioned exactly once */
-
- sources = (const char **)copy_sources->elts;
- qsort(sources, copy_sources->nelts, copy_sources->elt_size,
- (int (*)(const void *, const void *))svn_sort_compare_paths);
-
- unique_copy_sources = apr_hash_make(pool);
- for (i = 0; i < copy_sources->nelts; ++i)
- if ( (i == 0 || strcmp(sources[i-1], sources[i]))
- && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
- {
- apr_hash_set(unique_copy_sources, sources[i],
- APR_HASH_KEY_STRING, sources[i]);
- }
-
- /* no unique copy-from paths -> no moves */
-
- if (!apr_hash_count(unique_copy_sources))
- return;
-
- /* Replace all additions, replacements with a unique copy-from path,
- the correct copy-from rev and a matching deletion in this revision,
- with moves and move-replacements, respectively. */
-
- for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
- {
- const char *key;
- apr_ssize_t klen;
- svn_fs_path_change2_t *change, *copy_from_change;
-
- apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
- if ( change->copyfrom_rev != revision-1
- || !change->copyfrom_path
- || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
- APR_HASH_KEY_STRING))
- continue;
-
- copy_from_change = apr_hash_get(changes, change->copyfrom_path,
- APR_HASH_KEY_STRING);
- if (!copy_from_change || !is_deletion(copy_from_change))
- continue;
-
- /* There is a deletion of the ADD's copy-from path in *REVISION*.
- This can either be the same as in REVISION-1 (o.k.) or must have
- been replaced by some other node. However, that would imply that
- it still got deleted as part of the replacement, i.e. both cases
- are o.k. */
-
- switch (change->change_kind)
- {
- case svn_fs_path_change_add:
- change->change_kind = svn_fs_path_change_move;
- break;
-
- case svn_fs_path_change_replace:
- change->change_kind = svn_fs_path_change_movereplace;
- break;
-
- default:
- break;
- }
- }
-}
-
svn_error_t *
-svn_fs_paths_changed3(apr_hash_t **changed_paths_p,
+svn_fs_paths_changed2(apr_hash_t **changed_paths_p,
svn_fs_root_t *root,
- svn_move_behavior_t move_behavior,
- apr_pool_t *pool)
-{
- SVN_ERR(root->vtable->paths_changed(changed_paths_p, root, pool));
- switch(move_behavior)
- {
- case svn_move_behavior_no_moves:
- turn_moves_into_copies(*changed_paths_p, pool);
- break;
-
- case svn_move_behavior_auto_moves:
- turn_unique_copies_into_moves(*changed_paths_p, root->rev, pool);
- break;
-
- default:
- break;
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
apr_pool_t *pool)
{
- return svn_fs_paths_changed3(changed_paths_p, root,
- svn_move_behavior_no_moves, pool);
+ return root->vtable->paths_changed(changed_paths_p, root, pool);
}
svn_error_t *
@@ -1169,8 +1004,7 @@ svn_fs_paths_changed(apr_hash_t **change
apr_hash_t *changed_paths_new_structs;
apr_hash_index_t *hi;
- SVN_ERR(svn_fs_paths_changed3(&changed_paths_new_structs, root,
- svn_move_behavior_no_moves, pool));
+ SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
*changed_paths_p = apr_hash_make(pool);
for (hi = apr_hash_first(pool, changed_paths_new_structs);
hi;
Modified: subversion/trunk/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/log.c?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/log.c (original)
+++ subversion/trunk/subversion/libsvn_repos/log.c Thu Oct 24 10:21:00 2013
@@ -42,7 +42,6 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_subr_private.h"
-
svn_error_t *
svn_repos_check_revision_access(svn_repos_revision_access_level_t *access_level,
@@ -69,8 +68,7 @@ svn_repos_check_revision_access(svn_repo
/* Fetch the changes associated with REVISION. */
SVN_ERR(svn_fs_revision_root(&rev_root, fs, revision, pool));
- SVN_ERR(svn_fs_paths_changed3(&changes, rev_root,
- svn_move_behavior_explicit_moves, pool));
+ SVN_ERR(svn_fs_paths_changed2(&changes, rev_root, pool));
/* No changed paths? We're done. */
if (apr_hash_count(changes) == 0)
@@ -155,6 +153,147 @@ svn_repos_check_revision_access(svn_repo
return SVN_NO_ERROR;
}
+/* Return TRUE, if CHANGE deleted the node previously found at its target
+ path. */
+static svn_boolean_t
+is_deletion(svn_log_changed_path2_t *change)
+{
+ /* We need a 'N' action here ... */
+ return change->action == 'E'
+ || change->action == 'R'
+ || change->action == 'D';
+}
+
+/* Change all moves in CHANGES to ADD. Use POOL for temporary allocations.
+ */
+static void
+turn_moves_into_copies(apr_hash_t *changes,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_log_changed_path2_t *change;
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+
+ switch (change->action)
+ {
+ case 'M':
+ change->action = 'A';
+ break;
+
+ case 'E':
+ change->action = 'R';
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Replace ADDs with MOVes, if they are unique, have a matching deletion
+ * and if the copy-from revision is REVISION-1. Use POOL for temporary
+ * allocations.
+ */
+static void
+turn_unique_copies_into_moves(apr_hash_t *changes,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ apr_hash_t *unique_copy_sources;
+ const char **sources;
+ int i;
+
+ /* find all copy-from paths (ADD and MOV alike) */
+
+ svn_boolean_t any_deletion = FALSE;
+ apr_array_header_t *copy_sources
+ = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ svn_log_changed_path2_t *change;
+ apr_hash_this(hi, NULL, NULL, (void**)&change);
+
+ if (change->copyfrom_path && change->copyfrom_rev == revision-1)
+ APR_ARRAY_PUSH(copy_sources, const char *)
+ = change->copyfrom_path;
+
+ any_deletion |= is_deletion(change);
+ }
+
+ /* no suitable copy-from or no deletion -> no moves */
+
+ if (!copy_sources->nelts || !any_deletion)
+ return;
+
+ /* identify copy-from paths that have been mentioned exactly once */
+
+ sources = (const char **)copy_sources->elts;
+ qsort(sources, copy_sources->nelts, copy_sources->elt_size,
+ (int (*)(const void *, const void *))svn_sort_compare_paths);
+
+ unique_copy_sources = apr_hash_make(pool);
+ for (i = 0; i < copy_sources->nelts; ++i)
+ if ( (i == 0 || strcmp(sources[i-1], sources[i]))
+ && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
+ {
+ apr_hash_set(unique_copy_sources, sources[i],
+ APR_HASH_KEY_STRING, sources[i]);
+ }
+
+ /* no unique copy-from paths -> no moves */
+
+ if (!apr_hash_count(unique_copy_sources))
+ return;
+
+ /* Replace all additions, replacements with a unique copy-from path,
+ the correct copy-from rev and a matching deletion in this revision,
+ with moves and move-replacements, respectively. */
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_log_changed_path2_t *change, *copy_from_change;
+
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+ if ( change->copyfrom_rev != revision-1
+ || !change->copyfrom_path
+ || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
+ APR_HASH_KEY_STRING))
+ continue;
+
+ copy_from_change = apr_hash_get(changes, change->copyfrom_path,
+ APR_HASH_KEY_STRING);
+ if (!copy_from_change || !is_deletion(copy_from_change))
+ continue;
+
+ /* There is a deletion of the ADD's copy-from path in *REVISION*.
+ This can either be the same as in REVISION-1 (o.k.) or must have
+ been replaced by some other node. However, that would imply that
+ it still got deleted as part of the replacement, i.e. both cases
+ are o.k. */
+
+ switch (change->action)
+ {
+ case 'A':
+ change->action = 'V';
+ break;
+
+ case 'R':
+ change->action = 'E';
+ break;
+
+ default:
+ break;
+ }
+ }
+}
/* Store as keys in CHANGED the paths of all node in ROOT that show a
* significant change. "Significant" means that the text or
@@ -201,7 +340,7 @@ detect_changed(apr_hash_t **changed,
*changed = svn_hash__make(pool);
if (changes == NULL)
- SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
+ SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
if (apr_hash_count(changes) == 0)
/* No paths changed in this revision? Uh, sure, I guess the
@@ -368,6 +507,23 @@ detect_changed(apr_hash_t **changed,
return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE,
NULL, NULL);
+ /* at least some paths are readable. Post-process them. */
+ switch(move_behavior)
+ {
+ case svn_move_behavior_no_moves:
+ turn_moves_into_copies(*changed, pool);
+ break;
+
+ case svn_move_behavior_auto_moves:
+ turn_unique_copies_into_moves(*changed,
+ svn_fs_revision_root_revision(root),
+ pool);
+ break;
+
+ default:
+ break;
+ }
+
if (found_unreadable)
/* At least one changed-path was unreadable. */
return svn_error_create(SVN_ERR_AUTHZ_PARTIALLY_READABLE,
@@ -577,9 +733,7 @@ next_history_rev(const apr_array_header_
catalogs describing how mergeinfo values on paths (which are the
keys of those catalogs) were changed in REV. If *PREFETCHED_CAHNGES
already contains the changed paths for REV, use that. Otherwise,
- request that data and return it in *PREFETCHED_CHANGES.
- MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
- layer which changes to report as moves instead of additions. */
+ request that data and return it in *PREFETCHED_CHANGES. */
/* ### TODO: This would make a *great*, useful public function,
### svn_repos_fs_mergeinfo_changed()! -- cmpilato */
static svn_error_t *
@@ -588,7 +742,6 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
apr_hash_t **prefetched_changes,
svn_fs_t *fs,
svn_revnum_t rev,
- svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -609,8 +762,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
narrow down our search. */
SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
if (*prefetched_changes == NULL)
- SVN_ERR(svn_fs_paths_changed3(prefetched_changes, root, move_behavior,
- scratch_pool));
+ SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
/* No changed paths? We're done. */
if (apr_hash_count(*prefetched_changes) == 0)
@@ -802,9 +954,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
*ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
If *PREFETCHED_CAHNGES already contains the changed paths for
REV, use that. Otherwise, request that data and return it in
- *PREFETCHED_CHANGES. MOVE_BEHAVIOR tells the FS layer which
- changes to report as moves instead of additions.
- Use POOL for all allocations. */
+ *PREFETCHED_CHANGES. Use POOL for all allocations. */
static svn_error_t *
get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
svn_mergeinfo_t *deleted_mergeinfo,
@@ -812,7 +962,6 @@ get_combined_mergeinfo_changes(svn_merge
svn_fs_t *fs,
const apr_array_header_t *paths,
svn_revnum_t rev,
- svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -842,7 +991,7 @@ get_combined_mergeinfo_changes(svn_merge
err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
&added_mergeinfo_catalog,
prefetched_changes,
- fs, rev, move_behavior,
+ fs, rev,
scratch_pool, scratch_pool);
if (err)
{
@@ -2050,7 +2199,7 @@ do_logs(svn_fs_t *fs,
&deleted_mergeinfo,
&changes,
fs, cur_paths,
- current, move_behavior,
+ current,
iterpool, iterpool));
has_children = (apr_hash_count(added_mergeinfo) > 0
|| apr_hash_count(deleted_mergeinfo) > 0);
Modified: subversion/trunk/subversion/mod_dav_svn/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/merge.c?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/merge.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/merge.c Thu Oct 24 10:21:00 2013
@@ -115,7 +115,6 @@ static svn_error_t *
do_resources(const dav_svn_repos *repos,
svn_fs_root_t *root,
svn_revnum_t revision,
- svn_move_behavior_t move_behavior,
ap_filter_t *output,
apr_bucket_brigade *bb,
apr_pool_t *pool)
@@ -130,7 +129,7 @@ do_resources(const dav_svn_repos *repos,
and deleted things. Also, note that deleted things don't merit
responses of their own -- they are considered modifications to
their parent. */
- SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
+ SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
{
@@ -363,10 +362,7 @@ dav_svn__merge_response(ap_filter_t *out
### we can pass back the new version URL */
/* and go make me proud, boy! */
- serr = do_resources(repos, root, new_rev,
- /* report changes with no further interpretation */
- svn_move_behavior_explicit_moves,
- output, bb, pool);
+ serr = do_resources(repos, root, new_rev, output, bb, pool);
if (serr != NULL)
{
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
Modified: subversion/trunk/tools/server-side/svn-populate-node-origins-index.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/svn-populate-node-origins-index.c?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/svn-populate-node-origins-index.c (original)
+++ subversion/trunk/tools/server-side/svn-populate-node-origins-index.c Thu Oct 24 10:21:00 2013
@@ -77,8 +77,7 @@ index_revision_adds(int *count, svn_fs_t
*count = 0;
SVN_ERR(svn_fs_revision_root(&root, fs, revision, pool));
- SVN_ERR(svn_fs_paths_changed3(&changes, root,
- svn_move_behavior_explicit_moves, pool));
+ SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
/* No paths changed in this revision? Nothing to do. */
if (apr_hash_count(changes) == 0)
Modified: subversion/trunk/tools/server-side/svn-rep-sharing-stats.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/svn-rep-sharing-stats.c?rev=1535330&r1=1535329&r2=1535330&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/svn-rep-sharing-stats.c (original)
+++ subversion/trunk/tools/server-side/svn-rep-sharing-stats.c Thu Oct 24 10:21:00 2013
@@ -269,9 +269,7 @@ process_one_revision(svn_fs_t *fs,
/* Get the changed paths. */
SVN_ERR(svn_fs_revision_root(&rev_root, fs, revnum, scratch_pool));
- SVN_ERR(svn_fs_paths_changed3(&paths_changed, rev_root,
- svn_move_behavior_explicit_moves,
- scratch_pool));
+ SVN_ERR(svn_fs_paths_changed2(&paths_changed, rev_root, scratch_pool));
/* Iterate them. */
/* ### use iterpool? */