Author: julianfoad
Date: Fri Oct 19 11:36:31 2018
New Revision: 1844332
URL: http://svn.apache.org/viewvc?rev=1844332&view=rev
Log:
Refactor svnrdump's load-editor towards being reusable.
For issue SVN-4780: Factor out the dumpstream loader editor driver.
This pulls out the 'get a commit editor' and 'get props' functions into
callbacks.
* subversion/svnrdump/load_editor.c
(loader_fns_t,
commit_baton_t): New.
(parse_baton): Add callbacks.
(commit_callback,
fetch_base_func,
fetch_props_func,
fetch_kind_func,
get_shim_callbacks): Take a commit_baton_t instead of a revision_baton.
(fetch_props): New: a callback, split out from fetch_props_func().
(revision_start_edit): New.
(new_node_record,
close_revision): Get a commit editor via callback instead of directly.
(remove_node_props): Get props via callback instead of directly.
(revstart): New: a callback.
(get_dumpstream_loader): Initialize the callbacks.
Modified:
subversion/trunk/subversion/svnrdump/load_editor.c
Modified: subversion/trunk/subversion/svnrdump/load_editor.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnrdump/load_editor.c?rev=1844332&r1=1844331&r2=1844332&view=diff
==============================================================================
--- subversion/trunk/subversion/svnrdump/load_editor.c (original)
+++ subversion/trunk/subversion/svnrdump/load_editor.c Fri Oct 19 11:36:31 2018
@@ -45,6 +45,54 @@
/**
+ * A vtable that is driven by get_dumpstream_loader().
+ */
+typedef struct loader_fns_t
+{
+ /* Callback on starting a revision, to obtain an editor for the revision.
+ *
+ * This callback returns in *EDITOR and *EDIT_BATON an editor through which
+ * its caller will drive the changes for revision REVISION.
+ *
+ * This callback should call the editor's SET_TARGET_REVISION method if
+ * required.
+ *
+ * REV_PROPS holds the revision properties.
+ *
+ * POOL (and REV_PROPS) will persist until after the REVFINISH callback
+ * returns.
+ *
+ * Modelled on svn_ra_replay_revstart_callback_t.
+ */
+ svn_error_t *(*revstart)(
+ svn_revnum_t revision,
+ void *baton,
+ const svn_delta_editor_t **editor,
+ void **edit_baton,
+ apr_hash_t *rev_props,
+ apr_pool_t *pool);
+
+ /* Fetch the node props for ORIG_PATH @ ORIG_REV, a node of kind KIND.
+ *
+ * This callback is required if a non-deltas-format dump is parsed;
+ * otherwise it will not be called and may be null. If required and not
+ * provided, the loader will return SVN_ERR_UNSUPPORTED_FEATURE.
+ *
+ * Only regular props are needed. Any special kinds of property such as
+ * entry-props and DAV/WC-props will be ignored.
+ */
+ svn_error_t *(*fetch_props)(
+ apr_hash_t **props,
+ void *baton,
+ const char *orig_path,
+ svn_revnum_t orig_rev,
+ svn_node_kind_t kind,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+} loader_fns_t;
+
+/**
* General baton used by the parser functions.
*/
struct parse_baton
@@ -87,6 +135,9 @@ struct parse_baton
/* An hash containing specific revision properties to skip while
loading. */
apr_hash_t *skip_revprops;
+
+ const loader_fns_t *callbacks;
+ void *cb_baton;
};
/**
@@ -154,6 +205,15 @@ struct revision_baton
apr_pool_t *pool;
};
+/**
+ * Baton used for commit callback (and Ev2 shims).
+ */
+struct commit_baton_t
+{
+ svn_revnum_t rev;
+ struct parse_baton *pb;
+};
+
/* Record the mapping of FROM_REV to TO_REV in REV_MAP, ensuring that
@@ -192,8 +252,8 @@ commit_callback(const svn_commit_info_t
void *baton,
apr_pool_t *pool)
{
- struct revision_baton *rb = baton;
- struct parse_baton *pb = rb->pb;
+ struct commit_baton_t *cb = baton;
+ struct parse_baton *pb = cb->pb;
/* ### Don't print directly; generate a notification. */
if (! pb->quiet)
@@ -201,7 +261,7 @@ commit_callback(const svn_commit_info_t
commit_info->revision));
/* Add the mapping of the dumpstream revision to the committed revision. */
- set_revision_mapping(pb->rev_map, rb->rev, commit_info->revision);
+ set_revision_mapping(pb->rev_map, cb->rev, commit_info->revision);
/* If the incoming dump stream has non-contiguous revisions (e.g. from
using svndumpfilter --drop-empty-revs without --renumber-revs) then
@@ -209,18 +269,18 @@ commit_callback(const svn_commit_info_t
might not be able to map all mergeinfo source revisions to the correct
revisions in the target repos. */
if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
- && (rb->rev != pb->last_rev_mapped + 1))
+ && (cb->rev != pb->last_rev_mapped + 1))
{
svn_revnum_t i;
- for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
+ for (i = pb->last_rev_mapped + 1; i < cb->rev; i++)
{
set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
}
}
/* Update our "last revision mapped". */
- pb->last_rev_mapped = rb->rev;
+ pb->last_rev_mapped = cb->rev;
return SVN_NO_ERROR;
}
@@ -246,18 +306,18 @@ fetch_base_func(const char **filename,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- struct revision_baton *rb = baton;
+ struct commit_baton_t *cb = baton;
svn_stream_t *fstream;
svn_error_t *err;
if (! SVN_IS_VALID_REVNUM(base_revision))
- base_revision = rb->rev - 1;
+ base_revision = cb->rev - 1;
SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
svn_io_file_del_on_pool_cleanup,
result_pool, scratch_pool));
- err = svn_ra_get_file(rb->pb->aux_session, path, base_revision,
+ err = svn_ra_get_file(cb->pb->aux_session, path, base_revision,
fstream, NULL, NULL, scratch_pool);
if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
{
@@ -276,32 +336,26 @@ fetch_base_func(const char **filename,
}
static svn_error_t *
-fetch_props_func(apr_hash_t **props,
- void *baton,
- const char *path,
- svn_revnum_t base_revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+fetch_props(apr_hash_t **props,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ svn_node_kind_t node_kind,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- struct revision_baton *rb = baton;
- svn_node_kind_t node_kind;
-
- if (! SVN_IS_VALID_REVNUM(base_revision))
- base_revision = rb->rev - 1;
-
- SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
- &node_kind, scratch_pool));
+ struct parse_baton *pb = baton;
if (node_kind == svn_node_file)
{
- SVN_ERR(svn_ra_get_file(rb->pb->aux_session, path, base_revision,
+ SVN_ERR(svn_ra_get_file(pb->aux_session, path, base_revision,
NULL, NULL, props, result_pool));
}
else if (node_kind == svn_node_dir)
{
apr_array_header_t *tmp_props;
- SVN_ERR(svn_ra_get_dir2(rb->pb->aux_session, NULL, NULL, props, path,
+ SVN_ERR(svn_ra_get_dir2(pb->aux_session, NULL, NULL, props, path,
base_revision, 0 /* Dirent fields */,
result_pool));
tmp_props = svn_prop_hash_to_array(*props, result_pool);
@@ -318,25 +372,47 @@ fetch_props_func(apr_hash_t **props,
}
static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct commit_baton_t *cb = baton;
+ svn_node_kind_t node_kind;
+
+ if (! SVN_IS_VALID_REVNUM(base_revision))
+ base_revision = cb->rev - 1;
+
+ SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
+ &node_kind, scratch_pool));
+ SVN_ERR(fetch_props(props, cb->pb, path, base_revision, node_kind,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
fetch_kind_func(svn_node_kind_t *kind,
void *baton,
const char *path,
svn_revnum_t base_revision,
apr_pool_t *scratch_pool)
{
- struct revision_baton *rb = baton;
+ struct commit_baton_t *cb = baton;
if (! SVN_IS_VALID_REVNUM(base_revision))
- base_revision = rb->rev - 1;
+ base_revision = cb->rev - 1;
- SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
+ SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
kind, scratch_pool));
return SVN_NO_ERROR;
}
static svn_delta_shim_callbacks_t *
-get_shim_callbacks(struct revision_baton *rb,
+get_shim_callbacks(struct commit_baton_t *cb,
apr_pool_t *pool)
{
svn_delta_shim_callbacks_t *callbacks =
@@ -345,7 +421,7 @@ get_shim_callbacks(struct revision_baton
callbacks->fetch_props_func = fetch_props_func;
callbacks->fetch_kind_func = fetch_kind_func;
callbacks->fetch_base_func = fetch_base_func;
- callbacks->fetch_baton = rb;
+ callbacks->fetch_baton = cb;
return callbacks;
}
@@ -488,6 +564,30 @@ push_directory(struct revision_baton *rb
rb->db = child_db;
}
+/* Called to obtain an editor for the revision described by RB.
+ */
+static svn_error_t *
+revision_start_edit(struct revision_baton *rb,
+ apr_pool_t *scratch_pool)
+{
+ struct parse_baton *pb = rb->pb;
+ svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
+ void *child_baton;
+
+ SVN_ERR(pb->callbacks->revstart(rb->rev,
+ pb->cb_baton,
+ &pb->commit_editor, &pb->commit_edit_baton,
+ rb->revprop_table,
+ rb->pool));
+ SVN_ERR(pb->commit_editor->open_root(pb->commit_edit_baton,
+ head_rev_before_commit,
+ rb->pool, &child_baton));
+ /* child_baton corresponds to the root directory baton here */
+ push_directory(rb, child_baton, "", TRUE /*is_added*/,
+ NULL, SVN_INVALID_REVNUM);
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
new_node_record(void **node_baton,
apr_hash_t *headers,
@@ -496,7 +596,6 @@ new_node_record(void **node_baton,
{
struct revision_baton *rb = revision_baton;
const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
- void *commit_edit_baton = rb->pb->commit_edit_baton;
struct node_baton *nb;
svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
apr_hash_index_t *hi;
@@ -513,7 +612,6 @@ new_node_record(void **node_baton,
/* If the creation of commit_editor is pending, create it now and
open_root on it; also create a top-level directory baton. */
-
if (!commit_editor)
{
/* The revprop_table should have been filled in with important
@@ -526,23 +624,8 @@ new_node_record(void **node_baton,
svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_AUTHOR, NULL);
svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_DATE, NULL);
- SVN_ERR(svn_ra__register_editor_shim_callbacks(rb->pb->session,
- get_shim_callbacks(rb, rb->pool)));
- SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
- &commit_edit_baton, rb->revprop_table,
- commit_callback, revision_baton,
- NULL, FALSE, rb->pool));
-
- rb->pb->commit_editor = commit_editor;
- rb->pb->commit_edit_baton = commit_edit_baton;
-
- SVN_ERR(commit_editor->open_root(commit_edit_baton,
- head_rev_before_commit,
- rb->pool, &child_baton));
-
- /* child_baton corresponds to the root directory baton here */
- push_directory(rb, child_baton, "", TRUE /*is_added*/,
- NULL, SVN_INVALID_REVNUM);
+ SVN_ERR(revision_start_edit(rb, pool));
+ commit_editor = rb->pb->commit_editor;
}
for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
@@ -861,16 +944,14 @@ remove_node_props(void *baton)
/* Add-without-history; no "old" properties to worry about. */
return SVN_NO_ERROR;
- if (nb->kind == svn_node_file)
- {
- SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session,
- orig_path, orig_rev, NULL, NULL, &props, pool));
- }
- else /* nb->kind == svn_node_dir */
- {
- SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props,
- orig_path, orig_rev, 0, pool));
- }
+ if (! rb->pb->callbacks->fetch_props)
+ return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("This dumpstream reader requires a delta "
+ "format dumpstream"));
+ SVN_ERR(rb->pb->callbacks->fetch_props(&props,
+ rb->pb->cb_baton,
+ orig_path, orig_rev, nb->kind,
+ pool, pool));
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
{
@@ -987,20 +1068,12 @@ close_revision(void *baton)
}
else
{
- svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
- void *child_baton;
-
/* Legitimate revision with no node information */
- SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
- &commit_edit_baton, rb->revprop_table,
- commit_callback, baton,
- NULL, FALSE, rb->pool));
+ SVN_ERR(revision_start_edit(rb, rb->pool));
+ commit_editor = rb->pb->commit_editor;
+ commit_edit_baton = rb->pb->commit_edit_baton;
- SVN_ERR(commit_editor->open_root(commit_edit_baton,
- head_rev_before_commit,
- rb->pool, &child_baton));
-
- SVN_ERR(commit_editor->close_directory(child_baton, rb->pool));
+ SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
}
@@ -1042,6 +1115,30 @@ close_revision(void *baton)
return SVN_NO_ERROR;
}
+/* */
+static svn_error_t *
+revstart(svn_revnum_t revision,
+ void *baton,
+ const svn_delta_editor_t **editor_p,
+ void **edit_baton_p,
+ apr_hash_t *rev_props,
+ apr_pool_t *result_pool)
+{
+ struct parse_baton *pb = baton;
+ struct commit_baton_t *cb = apr_palloc(result_pool, sizeof(*cb));
+
+ cb->rev = revision;
+ cb->pb = pb;
+ SVN_ERR(svn_ra__register_editor_shim_callbacks(pb->session,
+ get_shim_callbacks(cb,
result_pool)));
+ SVN_ERR(svn_ra_get_commit_editor3(pb->session,
+ editor_p, edit_baton_p,
+ rev_props,
+ commit_callback, cb,
+ NULL, FALSE, result_pool));
+ return SVN_NO_ERROR;
+}
+
/* Return an implementation of the dumpstream parser API that will drive
* commits over the RA layer to the location described by SESSION.
*
@@ -1066,6 +1163,7 @@ get_dumpstream_loader(svn_repos_parse_fn
svn_repos_parse_fns3_t *parser;
struct parse_baton *parse_baton;
const char *session_url, *root_url, *parent_dir;
+ static const loader_fns_t callbacks = { revstart, fetch_props };
SVN_ERR(svn_ra_get_repos_root2(session, &root_url, pool));
SVN_ERR(svn_ra_get_session_url(session, &session_url, pool));
@@ -1096,6 +1194,8 @@ get_dumpstream_loader(svn_repos_parse_fn
parse_baton->last_rev_mapped = SVN_INVALID_REVNUM;
parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
parse_baton->skip_revprops = skip_revprops;
+ parse_baton->callbacks = &callbacks;
+ parse_baton->cb_baton = parse_baton;
*parser_p = parser;
*parse_baton_p = parse_baton;