You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gs...@apache.org on 2012/04/28 03:50:35 UTC
svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Author: gstein
Date: Sat Apr 28 01:50:35 2012
New Revision: 1331652
URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
Log:
For the Ev2 shims:
Revamp the Ev2/Ev1 shims by using struct change_node rather than the
funky "operation" records and the build() function. Each Ev2 callback
simply inserts a new change_node structure with some values in
it. Later, we use the path_driver to apply these change_node
structures to all modified paths.
This obsoletes huge chunks of code; to be removed in a future revision.
Test failures: log 38, merge 105.
* subversion/libsvn_delta/compat.c:
(process_actions): remove an incorrect assertion
(struct editor_baton): add a CHANGES hash
(insert_change): new helper function, similar to locate_change()
(add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
blocks for setting up change records
(add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
(alter_directory_cb, alter_file_cb): set up change records, noting
that the record could have been created by an earlier copy/move.
(copy_cb): set up change records. use the FETCH_KIND_FUNC callback
to fetch kind information about the source (so we know what Ev1
function to invoke for the destination)
(move_cb): set up a change record for the source/deletion side, and
the destination/copy side. use the FETCH_KIND_FUNC callback.
(drive_ev1_props): helpful utility function to drive a series of
single property changes (adds, modifies, deletes) to the Ev1
editor. this helper also manages the special "unlock" mechanism
(apply_change): apply all changes described in a change_node
structure to a specified node
(drive_changes): if any changes have been made (eg. start_edit_func
was called an the root baton opened), then prepare a list of paths
for the path_driver, and then run the sucker to make all the
necessary edits. we have some special sneakiness to ensure the
path_driver doesn't call open_root() a second time.
(complete_cb, abort_cb): use drive_changes() rather than drive_root()
(start_edit_func): leave a note about early-open of the root
(do_unlock): record UNLOCK in the change_node. this will be handled
by drive_ev1_props() later.
(svn_delta__editor_from_delta): create the new CHANGES hash
Modified:
subversion/trunk/subversion/libsvn_delta/compat.c
Modified: subversion/trunk/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/compat.c?rev=1331652&r1=1331651&r2=1331652&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/compat.c (original)
+++ subversion/trunk/subversion/libsvn_delta/compat.c Sat Apr 28 01:50:35 2012
@@ -434,8 +434,12 @@ process_actions(struct ev2_edit_baton *e
if (props || contents)
{
/* Changes to properties or content should have indicated the revision
- it was intending to change. */
+ it was intending to change.
+
+ Oop. Not true. The node may be locally-added. */
+#if 0
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(change->changing));
+#endif
if (kind == svn_kind_dir)
SVN_ERR(svn_editor_alter_directory(eb->editor, repos_relpath,
@@ -1042,10 +1046,38 @@ struct editor_baton
const char *repos_root;
const char *base_relpath;
+ /* REPOS_RELPATH -> struct change_node * */
+ apr_hash_t *changes;
+
apr_pool_t *edit_pool;
};
+/* Insert a new change for RELPATH, or return an existing one. */
+static struct change_node *
+insert_change(const char *relpath,
+ apr_hash_t *changes)
+{
+ apr_pool_t *result_pool;
+ struct change_node *change;
+
+ change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
+ if (change != NULL)
+ return change;
+
+ result_pool = apr_hash_pool_get(changes);
+
+ /* Return an empty change. Callers will tweak as needed. */
+ change = apr_pcalloc(result_pool, sizeof(*change));
+ change->changing = SVN_INVALID_REVNUM;
+ change->deleting = SVN_INVALID_REVNUM;
+
+ apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
+
+ return change;
+}
+
+
/* Find the operation associated with PATH, which is a single-path
component representing a child of the path represented by
OPERATION. If no such child operation exists, create a new one of
@@ -1292,6 +1324,15 @@ add_directory_cb(void *baton,
NULL, SVN_INVALID_REVNUM, props,
NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD;
+ change->kind = svn_kind_dir;
+ change->deleting = replaces_rev;
+ change->props = apr_hash_copy(eb->edit_pool, props);
+ }
+
return SVN_NO_ERROR;
}
@@ -1342,6 +1383,17 @@ add_file_cb(void *baton,
NULL, SVN_INVALID_REVNUM, props,
NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD;
+ change->kind = svn_kind_file;
+ change->deleting = replaces_rev;
+ change->props = apr_hash_copy(eb->edit_pool, props);
+ change->contents_abspath = tmp_filename;
+ change->checksum = svn_checksum_dup(md5_checksum, eb->edit_pool);
+ }
+
return SVN_NO_ERROR;
}
@@ -1354,6 +1406,7 @@ add_symlink_cb(void *baton,
svn_revnum_t replaces_rev,
apr_pool_t *scratch_pool)
{
+#if 0
struct editor_baton *eb = baton;
if (SVN_IS_VALID_REVNUM(replaces_rev))
@@ -1365,6 +1418,18 @@ add_symlink_cb(void *baton,
NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
}
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD;
+ change->kind = svn_kind_symlink;
+ change->deleting = replaces_rev;
+ change->props = apr_hash_copy(eb->edit_pool, props);
+ /* ### target */
+ }
+#endif
+
+ SVN__NOT_IMPLEMENTED();
return SVN_NO_ERROR;
}
@@ -1382,6 +1447,14 @@ add_absent_cb(void *baton,
NULL, SVN_INVALID_REVNUM,
NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD_ABSENT;
+ change->kind = kind;
+ change->deleting = replaces_rev;
+ }
+
return SVN_NO_ERROR;
}
@@ -1401,6 +1474,16 @@ alter_directory_cb(void *baton,
NULL, SVN_INVALID_REVNUM,
props, NULL, NULL, revision, scratch_pool));
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ /* Note: this node may already have information in CHANGE as a result
+ of an earlier copy/move operation. */
+ change->kind = svn_kind_dir;
+ change->changing = revision;
+ change->props = apr_hash_copy(eb->edit_pool, props);
+ }
+
return SVN_NO_ERROR;
}
@@ -1450,6 +1533,23 @@ alter_file_cb(void *baton,
props, NULL, NULL, revision, scratch_pool));
}
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ /* Note: this node may already have information in CHANGE as a result
+ of an earlier copy/move operation. */
+
+ change->kind = svn_kind_file;
+ change->changing = revision;
+ if (props != NULL)
+ change->props = apr_hash_copy(eb->edit_pool, props);
+ if (contents != NULL)
+ {
+ change->contents_abspath = tmp_filename;
+ change->checksum = svn_checksum_dup(md5_checksum, eb->edit_pool);
+ }
+ }
+
return SVN_NO_ERROR;
}
@@ -1483,6 +1583,14 @@ delete_cb(void *baton,
NULL, revision, NULL, NULL, NULL, SVN_INVALID_REVNUM,
scratch_pool));
+ {
+ struct change_node *change = insert_change(relpath, eb->changes);
+
+ change->action = RESTRUCTURE_DELETE;
+ /* change->kind = svn_kind_unknown; */
+ change->deleting = revision;
+ }
+
return SVN_NO_ERROR;
}
@@ -1510,6 +1618,25 @@ copy_cb(void *baton,
src_relpath, src_revision, NULL, NULL, NULL,
SVN_INVALID_REVNUM, scratch_pool));
+ {
+ struct change_node *change = insert_change(dst_relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD;
+ /* change->kind = svn_kind_unknown; */
+ change->deleting = replaces_rev;
+ change->copyfrom_path = apr_pstrdup(eb->edit_pool, src_relpath);
+ change->copyfrom_rev = src_revision;
+
+ /* We need the source's kind to know whether to call add_directory()
+ or add_file() later on. */
+ SVN_ERR(eb->fetch_kind_func(&change->kind, eb->fetch_kind_baton,
+ change->copyfrom_path,
+ change->copyfrom_rev,
+ scratch_pool));
+
+ /* Note: this node may later have alter_*() called on it. */
+ }
+
return SVN_NO_ERROR;
}
@@ -1541,6 +1668,33 @@ move_cb(void *baton,
src_relpath, src_revision, NULL, NULL, NULL,
SVN_INVALID_REVNUM, scratch_pool));
+ /* Remap a move into a DELETE + COPY. */
+ {
+ struct change_node *change = insert_change(src_relpath, eb->changes);
+
+ change->action = RESTRUCTURE_DELETE;
+ /* change->kind = svn_kind_unknown; */
+ change->deleting = src_revision;
+ }
+ {
+ struct change_node *change = insert_change(dst_relpath, eb->changes);
+
+ change->action = RESTRUCTURE_ADD;
+ /* change->kind = svn_kind_unknown; */
+ change->deleting = replaces_rev;
+ change->copyfrom_path = apr_pstrdup(eb->edit_pool, src_relpath);
+ change->copyfrom_rev = src_revision;
+
+ /* We need the source's kind to know whether to call add_directory()
+ or add_file() later on. */
+ SVN_ERR(eb->fetch_kind_func(&change->kind, eb->fetch_kind_baton,
+ change->copyfrom_path,
+ change->copyfrom_rev,
+ scratch_pool));
+
+ /* Note: this node may later have alter_*() called on it. */
+ }
+
return SVN_NO_ERROR;
}
@@ -1749,6 +1903,270 @@ drive_root(struct operation *root,
return SVN_NO_ERROR;
}
+
+static svn_error_t *
+drive_ev1_props(const struct editor_baton *eb,
+ const char *repos_relpath,
+ const struct change_node *change,
+ void *node_baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_t *old_props;
+ apr_array_header_t *propdiffs;
+ const char *ev1_relpath;
+ int i;
+
+ /* If there are no properties to install, then just exit. */
+ if (change->props == NULL)
+ return SVN_NO_ERROR;
+
+ if (change->copyfrom_path)
+ {
+ /* The pristine properties are from the copy/move source. */
+ SVN_ERR(eb->fetch_props_func(&old_props, eb->fetch_props_baton,
+ change->copyfrom_path,
+ change->copyfrom_rev,
+ scratch_pool, iterpool));
+ }
+ else if (change->action == RESTRUCTURE_ADD)
+ {
+ /* Locally-added nodes have no pristine properties.
+
+ Note: we can use iterpool; this hash only needs to survive to
+ the propdiffs call, and there are no contents to preserve. */
+ old_props = apr_hash_make(iterpool);
+ }
+ else
+ {
+ /* Fetch the pristine properties for whatever we're editing. */
+ SVN_ERR(eb->fetch_props_func(&old_props, eb->fetch_props_baton,
+ repos_relpath, change->changing,
+ scratch_pool, iterpool));
+ }
+
+ SVN_ERR(svn_prop_diffs(&propdiffs, change->props, old_props, scratch_pool));
+
+ ev1_relpath = svn_relpath_skip_ancestor(eb->base_relpath, repos_relpath);
+
+ for (i = 0; i < propdiffs->nelts; i++)
+ {
+ /* Note: the array returned by svn_prop_diffs() is an array of
+ actual structures, not pointers to them. */
+ const svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
+
+ svn_pool_clear(iterpool);
+
+ if (change->kind == svn_kind_dir)
+ SVN_ERR(eb->deditor->change_dir_prop(node_baton,
+ prop->name, prop->value,
+ iterpool));
+ else
+ SVN_ERR(eb->deditor->change_file_prop(node_baton,
+ prop->name, prop->value,
+ iterpool));
+ }
+
+ /* Handle the funky unlock protocol. Note: only possibly on files. */
+ if (change->unlock)
+ {
+ SVN_ERR_ASSERT(change->kind == svn_kind_file);
+ SVN_ERR(eb->deditor->change_file_prop(node_baton,
+ SVN_PROP_ENTRY_LOCK_TOKEN, NULL,
+ iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
+
+/* Conforms to svn_delta_path_driver_cb_func_t */
+static svn_error_t *
+apply_change(void **dir_baton,
+ void *parent_baton,
+ void *callback_baton,
+ const char *ev1_relpath,
+ apr_pool_t *result_pool)
+{
+ /* ### fix this? */
+ apr_pool_t *scratch_pool = result_pool;
+ const struct editor_baton *eb = callback_baton;
+ const struct change_node *change;
+ const char *relpath;
+ void *file_baton = NULL;
+
+ /* Typically, we are not creating new directory batons. */
+ *dir_baton = NULL;
+
+ relpath = svn_relpath_join(eb->base_relpath, ev1_relpath, scratch_pool);
+ change = apr_hash_get(eb->changes, relpath, APR_HASH_KEY_STRING);
+
+ /* The callback should only be called for paths in CHANGES. */
+ SVN_ERR_ASSERT(change != NULL);
+
+ /* Are we editing the root of the tree? */
+ if (parent_baton == NULL)
+ {
+ /* The root was opened in start_edit_func() */
+ *dir_baton = eb->root.baton;
+
+ /* Only property edits are allowed on the root. */
+ SVN_ERR_ASSERT(change->action == RESTRUCTURE_NONE);
+ SVN_ERR(drive_ev1_props(eb, relpath, change, *dir_baton, scratch_pool));
+
+ /* No further action possible for the root. */
+ return SVN_NO_ERROR;
+ }
+
+ if (change->action == RESTRUCTURE_DELETE)
+ {
+ SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
+ parent_baton, scratch_pool));
+
+ /* No futher action possible for this node. */
+ return SVN_NO_ERROR;
+ }
+
+ /* If we're not deleting this node, then we should know its kind. */
+ SVN_ERR_ASSERT(change->kind != svn_kind_unknown);
+
+ if (change->action == RESTRUCTURE_ADD_ABSENT)
+ {
+ if (change->kind == svn_kind_dir)
+ SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton,
+ scratch_pool));
+ else
+ SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton,
+ scratch_pool));
+
+ /* No further action possible for this node. */
+ return SVN_NO_ERROR;
+ }
+ /* RESTRUCTURE_NONE or RESTRUCTURE_ADD */
+
+ if (change->action == RESTRUCTURE_ADD)
+ {
+ const char *copyfrom_url = NULL;
+ svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
+
+ /* Do we have an old node to delete first? */
+ if (SVN_IS_VALID_REVNUM(change->deleting))
+ SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
+ parent_baton, scratch_pool));
+
+ /* Are we copying the node from somewhere? */
+ if (change->copyfrom_path)
+ {
+ if (eb->repos_root)
+ copyfrom_url = svn_path_url_add_component2(eb->repos_root,
+ change->copyfrom_path,
+ scratch_pool);
+ else
+ /* ### prefix with "/" ? */
+ copyfrom_url = change->copyfrom_path;
+
+ copyfrom_rev = change->copyfrom_rev;
+ }
+
+ if (change->kind == svn_kind_dir)
+ SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton,
+ copyfrom_url, copyfrom_rev,
+ result_pool, dir_baton));
+ else
+ SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton,
+ copyfrom_url, copyfrom_rev,
+ result_pool, &file_baton));
+ }
+ else
+ {
+ if (change->kind == svn_kind_dir)
+ SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton,
+ change->changing,
+ result_pool, dir_baton));
+ else
+ SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton,
+ change->changing,
+ result_pool, &file_baton));
+ }
+
+ /* Apply any properties in CHANGE to the node. */
+ if (change->kind == svn_kind_dir)
+ SVN_ERR(drive_ev1_props(eb, relpath, change, *dir_baton, scratch_pool));
+ else
+ SVN_ERR(drive_ev1_props(eb, relpath, change, file_baton, scratch_pool));
+
+ if (change->contents_abspath)
+ {
+ svn_txdelta_window_handler_t handler;
+ void *handler_baton;
+ svn_stream_t *contents;
+
+ /* ### would be nice to have a BASE_CHECKSUM, but hey: this is the
+ ### shim code... */
+ SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool,
+ &handler, &handler_baton));
+ SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
+ scratch_pool, scratch_pool));
+ /* ### it would be nice to send a true txdelta here, but whatever. */
+ SVN_ERR(svn_txdelta_send_stream(contents, handler, handler_baton,
+ NULL, scratch_pool));
+ SVN_ERR(svn_stream_close(contents));
+ }
+
+ if (file_baton)
+ {
+ const char *digest = svn_checksum_to_cstring(change->checksum,
+ scratch_pool);
+
+ SVN_ERR(eb->deditor->close_file(file_baton, digest, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+drive_changes(const struct editor_baton *eb,
+ apr_pool_t *scratch_pool)
+{
+ struct change_node *change;
+ apr_array_header_t *paths = apr_array_make(scratch_pool, 10,
+ sizeof(const char *));;
+ apr_hash_index_t *hi;
+
+ /* If we never opened a root baton, then the caller aborted the editor
+ before it even began. There is nothing to do. Bail. */
+ if (eb->root.baton == NULL)
+ return SVN_NO_ERROR;
+
+ /* We need to make the path driver believe we want to make changes to
+ the root. Otherwise, it will attempt an open_root(), which we already
+ did in start_edit_func(). We can forge up a change record, if one
+ does not already exist. */
+ change = insert_change(eb->base_relpath, eb->changes);
+ change->kind = svn_kind_dir;
+ /* No property changes (tho they might exist from a real change). */
+
+ for (hi = apr_hash_first(scratch_pool, eb->changes); hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *relpath = svn__apr_hash_index_key(hi);
+ const char *ev1_relpath = svn_relpath_skip_ancestor(eb->base_relpath,
+ relpath);
+ APR_ARRAY_PUSH(paths, const char *) = ev1_relpath;
+ }
+
+ /* Note: dropping const on the callback_baton */
+ SVN_ERR(svn_delta_path_driver(eb->deditor, eb->dedit_baton,
+ eb->root.base_revision, paths,
+ apply_change, (void *)eb,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -1758,7 +2176,11 @@ complete_cb(void *baton,
svn_error_t *err;
/* Drive the tree we've created. */
+#if 1
+ err = drive_changes(eb, scratch_pool);
+#else
err = drive_root(&eb->root, eb->deditor, *eb->make_abs_paths, scratch_pool);
+#endif
if (!err)
{
err = svn_error_compose_create(err, eb->deditor->close_edit(
@@ -1785,7 +2207,11 @@ abort_cb(void *baton,
point. */
/* Drive the tree we've created. */
+#if 1
+ err = drive_changes(eb, scratch_pool);
+#else
err = drive_root(&eb->root, eb->deditor, *eb->make_abs_paths, scratch_pool);
+#endif
err2 = eb->deditor->abort_edit(eb->dedit_baton, scratch_pool);
@@ -1807,6 +2233,10 @@ start_edit_func(void *baton,
struct editor_baton *eb = baton;
eb->root.base_revision = base_revision;
+
+ /* For some Ev1 editors (such as the repos commit editor), the root must
+ be open before can invoke any callbacks. The open_root() call sets up
+ stuff (eg. open an FS txn) which will be needed. */
SVN_ERR(eb->deditor->open_root(eb->dedit_baton, eb->root.base_revision,
eb->edit_pool, &eb->root.baton));
@@ -1837,6 +2267,14 @@ do_unlock(void *baton,
struct operation *operation = &eb->root;
int i;
+ {
+ /* PATH is REPOS_RELPATH */
+ struct change_node *change = insert_change(path, eb->changes);
+
+ /* We will need to propagate a deletion of SVN_PROP_ENTRY_LOCK_TOKEN */
+ change->unlock = TRUE;
+ }
+
/* Look for any previous operations we've recognized for PATH. If
any of PATH's ancestors have not yet been traversed, we'll be
creating OP_OPEN operations for them as we walk down PATH's path
@@ -1931,6 +2369,8 @@ svn_delta__editor_from_delta(svn_editor_
eb->repos_root = apr_pstrdup(result_pool, repos_root);
eb->base_relpath = apr_pstrdup(result_pool, base_relpath);
+ eb->changes = apr_hash_make(result_pool);
+
eb->fetch_kind_func = fetch_kind_func;
eb->fetch_kind_baton = fetch_kind_baton;
eb->fetch_props_func = fetch_props_func;
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Greg Stein <gs...@gmail.com>.
btw, I fixed log 38, and am re-running tests to ensure that my hacky
fix doesn't break other stuff. merge 105 is unrelated to the shims,
and will send separate email.
On Fri, Apr 27, 2012 at 22:10, Hyrum K Wright <hy...@wandisco.com> wrote:
> Hey cool! I'm glad my first hack at the backward compat code is
> getting a good look / knife.
>
> As an aside: I'm going to be preoccupied by other stuff for the next
> several days, but hope to dig back in towards the end of next week, if
> you haven't finished all the Ev2 work by then. :P
>
> -Hyrum
>
> On Fri, Apr 27, 2012 at 8:59 PM, Greg Stein <gs...@gmail.com> wrote:
>> Hyrum,
>>
>> I think you're going to like this one :-) ... all of the build() and
>> operation stuff is now gone. Rather than path elements and
>> intermediate batons manually, I switched the code to rely on the
>> path_driver. It also shares the change_node structure with the Ev1/Ev2
>> shim.
>>
>> In essence, struct change_node records all possible changes to a
>> single node. Both shims just accumulate those, and at replay time
>> "does the right thing". Shoot... you could serialize a sequence of
>> those structures, send them over the wire, and replay them to perform
>> an edit. Not that we're gonna do that any time soon, but the semantics
>> are there.
>>
>> Anyhow... I haven't deleted the old code yet. I want to use some of
>> that for reference to track down these two new test failures. Then I'm
>> gonna take a huge axe to compat.c to trim it back. Woot!
>>
>> Cheers,
>> -g
>>
>> ---------- Forwarded message ----------
>> From: <gs...@apache.org>
>> Date: Fri, Apr 27, 2012 at 21:50
>> Subject: svn commit: r1331652 -
>> /subversion/trunk/subversion/libsvn_delta/compat.c
>> To: commits@subversion.apache.org
>>
>>
>> Author: gstein
>> Date: Sat Apr 28 01:50:35 2012
>> New Revision: 1331652
>>
>> URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
>> Log:
>> For the Ev2 shims:
>>
>> Revamp the Ev2/Ev1 shims by using struct change_node rather than the
>> funky "operation" records and the build() function. Each Ev2 callback
>> simply inserts a new change_node structure with some values in
>> it. Later, we use the path_driver to apply these change_node
>> structures to all modified paths.
>>
>> This obsoletes huge chunks of code; to be removed in a future revision.
>>
>> Test failures: log 38, merge 105.
>>
>> * subversion/libsvn_delta/compat.c:
>> (process_actions): remove an incorrect assertion
>> (struct editor_baton): add a CHANGES hash
>> (insert_change): new helper function, similar to locate_change()
>> (add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
>> blocks for setting up change records
>> (add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
>> (alter_directory_cb, alter_file_cb): set up change records, noting
>> that the record could have been created by an earlier copy/move.
>> (copy_cb): set up change records. use the FETCH_KIND_FUNC callback
>> to fetch kind information about the source (so we know what Ev1
>> function to invoke for the destination)
>> (move_cb): set up a change record for the source/deletion side, and
>> the destination/copy side. use the FETCH_KIND_FUNC callback.
>> (drive_ev1_props): helpful utility function to drive a series of
>> single property changes (adds, modifies, deletes) to the Ev1
>> editor. this helper also manages the special "unlock" mechanism
>> (apply_change): apply all changes described in a change_node
>> structure to a specified node
>> (drive_changes): if any changes have been made (eg. start_edit_func
>> was called an the root baton opened), then prepare a list of paths
>> for the path_driver, and then run the sucker to make all the
>> necessary edits. we have some special sneakiness to ensure the
>> path_driver doesn't call open_root() a second time.
>> (complete_cb, abort_cb): use drive_changes() rather than drive_root()
>> (start_edit_func): leave a note about early-open of the root
>> (do_unlock): record UNLOCK in the change_node. this will be handled
>> by drive_ev1_props() later.
>> (svn_delta__editor_from_delta): create the new CHANGES hash
>>
>> [snip]
>
>
>
> --
>
> uberSVN: Apache Subversion Made Easy
> http://www.uberSVN.com/
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Hyrum K Wright <hy...@wandisco.com>.
Hey cool! I'm glad my first hack at the backward compat code is
getting a good look / knife.
As an aside: I'm going to be preoccupied by other stuff for the next
several days, but hope to dig back in towards the end of next week, if
you haven't finished all the Ev2 work by then. :P
-Hyrum
On Fri, Apr 27, 2012 at 8:59 PM, Greg Stein <gs...@gmail.com> wrote:
> Hyrum,
>
> I think you're going to like this one :-) ... all of the build() and
> operation stuff is now gone. Rather than path elements and
> intermediate batons manually, I switched the code to rely on the
> path_driver. It also shares the change_node structure with the Ev1/Ev2
> shim.
>
> In essence, struct change_node records all possible changes to a
> single node. Both shims just accumulate those, and at replay time
> "does the right thing". Shoot... you could serialize a sequence of
> those structures, send them over the wire, and replay them to perform
> an edit. Not that we're gonna do that any time soon, but the semantics
> are there.
>
> Anyhow... I haven't deleted the old code yet. I want to use some of
> that for reference to track down these two new test failures. Then I'm
> gonna take a huge axe to compat.c to trim it back. Woot!
>
> Cheers,
> -g
>
> ---------- Forwarded message ----------
> From: <gs...@apache.org>
> Date: Fri, Apr 27, 2012 at 21:50
> Subject: svn commit: r1331652 -
> /subversion/trunk/subversion/libsvn_delta/compat.c
> To: commits@subversion.apache.org
>
>
> Author: gstein
> Date: Sat Apr 28 01:50:35 2012
> New Revision: 1331652
>
> URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
> Log:
> For the Ev2 shims:
>
> Revamp the Ev2/Ev1 shims by using struct change_node rather than the
> funky "operation" records and the build() function. Each Ev2 callback
> simply inserts a new change_node structure with some values in
> it. Later, we use the path_driver to apply these change_node
> structures to all modified paths.
>
> This obsoletes huge chunks of code; to be removed in a future revision.
>
> Test failures: log 38, merge 105.
>
> * subversion/libsvn_delta/compat.c:
> (process_actions): remove an incorrect assertion
> (struct editor_baton): add a CHANGES hash
> (insert_change): new helper function, similar to locate_change()
> (add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
> blocks for setting up change records
> (add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
> (alter_directory_cb, alter_file_cb): set up change records, noting
> that the record could have been created by an earlier copy/move.
> (copy_cb): set up change records. use the FETCH_KIND_FUNC callback
> to fetch kind information about the source (so we know what Ev1
> function to invoke for the destination)
> (move_cb): set up a change record for the source/deletion side, and
> the destination/copy side. use the FETCH_KIND_FUNC callback.
> (drive_ev1_props): helpful utility function to drive a series of
> single property changes (adds, modifies, deletes) to the Ev1
> editor. this helper also manages the special "unlock" mechanism
> (apply_change): apply all changes described in a change_node
> structure to a specified node
> (drive_changes): if any changes have been made (eg. start_edit_func
> was called an the root baton opened), then prepare a list of paths
> for the path_driver, and then run the sucker to make all the
> necessary edits. we have some special sneakiness to ensure the
> path_driver doesn't call open_root() a second time.
> (complete_cb, abort_cb): use drive_changes() rather than drive_root()
> (start_edit_func): leave a note about early-open of the root
> (do_unlock): record UNLOCK in the change_node. this will be handled
> by drive_ev1_props() later.
> (svn_delta__editor_from_delta): create the new CHANGES hash
>
> [snip]
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Fwd: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Greg Stein <gs...@gmail.com>.
Hyrum,
I think you're going to like this one :-) ... all of the build() and
operation stuff is now gone. Rather than path elements and
intermediate batons manually, I switched the code to rely on the
path_driver. It also shares the change_node structure with the Ev1/Ev2
shim.
In essence, struct change_node records all possible changes to a
single node. Both shims just accumulate those, and at replay time
"does the right thing". Shoot... you could serialize a sequence of
those structures, send them over the wire, and replay them to perform
an edit. Not that we're gonna do that any time soon, but the semantics
are there.
Anyhow... I haven't deleted the old code yet. I want to use some of
that for reference to track down these two new test failures. Then I'm
gonna take a huge axe to compat.c to trim it back. Woot!
Cheers,
-g
---------- Forwarded message ----------
From: <gs...@apache.org>
Date: Fri, Apr 27, 2012 at 21:50
Subject: svn commit: r1331652 -
/subversion/trunk/subversion/libsvn_delta/compat.c
To: commits@subversion.apache.org
Author: gstein
Date: Sat Apr 28 01:50:35 2012
New Revision: 1331652
URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
Log:
For the Ev2 shims:
Revamp the Ev2/Ev1 shims by using struct change_node rather than the
funky "operation" records and the build() function. Each Ev2 callback
simply inserts a new change_node structure with some values in
it. Later, we use the path_driver to apply these change_node
structures to all modified paths.
This obsoletes huge chunks of code; to be removed in a future revision.
Test failures: log 38, merge 105.
* subversion/libsvn_delta/compat.c:
(process_actions): remove an incorrect assertion
(struct editor_baton): add a CHANGES hash
(insert_change): new helper function, similar to locate_change()
(add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
blocks for setting up change records
(add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
(alter_directory_cb, alter_file_cb): set up change records, noting
that the record could have been created by an earlier copy/move.
(copy_cb): set up change records. use the FETCH_KIND_FUNC callback
to fetch kind information about the source (so we know what Ev1
function to invoke for the destination)
(move_cb): set up a change record for the source/deletion side, and
the destination/copy side. use the FETCH_KIND_FUNC callback.
(drive_ev1_props): helpful utility function to drive a series of
single property changes (adds, modifies, deletes) to the Ev1
editor. this helper also manages the special "unlock" mechanism
(apply_change): apply all changes described in a change_node
structure to a specified node
(drive_changes): if any changes have been made (eg. start_edit_func
was called an the root baton opened), then prepare a list of paths
for the path_driver, and then run the sucker to make all the
necessary edits. we have some special sneakiness to ensure the
path_driver doesn't call open_root() a second time.
(complete_cb, abort_cb): use drive_changes() rather than drive_root()
(start_edit_func): leave a note about early-open of the root
(do_unlock): record UNLOCK in the change_node. this will be handled
by drive_ev1_props() later.
(svn_delta__editor_from_delta): create the new CHANGES hash
[snip]
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Greg Stein <gs...@gmail.com>.
On Mon, Apr 30, 2012 at 23:31, Hyrum K Wright <hy...@wandisco.com> wrote:
> On Mon, Apr 30, 2012 at 10:02 PM, Greg Stein <gs...@gmail.com> wrote:
>>
>> On Apr 30, 2012 9:38 PM, "Hyrum K Wright" <hy...@wandisco.com> wrote:
>>>...
>>> As the key of the hash, RELPATH should be duplicated into a pool with
>>> sufficient lifetime.
>>
>> Good catch! Fixed in r1332508.
>
> Thanks. For the same reason, you probably want to
> s/apr_hash_copy/svn_prop_hash_dup/ over compat.c. The former only
> duplicates the hash, not the keys or the contents, while the latter
> will ensure the prophash has the same lifetime as the change it
> belongs to.
Oop! You're right. Will do after I commit my work-in-progress.
Thx,
-g
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Hyrum K Wright <hy...@wandisco.com>.
On Mon, Apr 30, 2012 at 10:02 PM, Greg Stein <gs...@gmail.com> wrote:
>
> On Apr 30, 2012 9:38 PM, "Hyrum K Wright" <hy...@wandisco.com> wrote:
>>...
>
>
>> > +/* Insert a new change for RELPATH, or return an existing one. */
>> > +static struct change_node *
>> > +insert_change(const char *relpath,
>> > + apr_hash_t *changes)
>> > +{
>> > + apr_pool_t *result_pool;
>> > + struct change_node *change;
>> > +
>> > + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
>> > + if (change != NULL)
>> > + return change;
>> > +
>> > + result_pool = apr_hash_pool_get(changes);
>> > +
>> > + /* Return an empty change. Callers will tweak as needed. */
>> > + change = apr_pcalloc(result_pool, sizeof(*change));
>> > + change->changing = SVN_INVALID_REVNUM;
>> > + change->deleting = SVN_INVALID_REVNUM;
>> > +
>> > + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
>>
>> As the key of the hash, RELPATH should be duplicated into a pool with
>> sufficient lifetime.
>
> Good catch! Fixed in r1332508.
Thanks. For the same reason, you probably want to
s/apr_hash_copy/svn_prop_hash_dup/ over compat.c. The former only
duplicates the hash, not the keys or the contents, while the latter
will ensure the prophash has the same lifetime as the change it
belongs to.
-Hyrum
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Hyrum K Wright <hy...@wandisco.com>.
On Mon, Apr 30, 2012 at 10:02 PM, Greg Stein <gs...@gmail.com> wrote:
>
> On Apr 30, 2012 9:38 PM, "Hyrum K Wright" <hy...@wandisco.com> wrote:
>>...
>
>
>> > +/* Insert a new change for RELPATH, or return an existing one. */
>> > +static struct change_node *
>> > +insert_change(const char *relpath,
>> > + apr_hash_t *changes)
>> > +{
>> > + apr_pool_t *result_pool;
>> > + struct change_node *change;
>> > +
>> > + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
>> > + if (change != NULL)
>> > + return change;
>> > +
>> > + result_pool = apr_hash_pool_get(changes);
>> > +
>> > + /* Return an empty change. Callers will tweak as needed. */
>> > + change = apr_pcalloc(result_pool, sizeof(*change));
>> > + change->changing = SVN_INVALID_REVNUM;
>> > + change->deleting = SVN_INVALID_REVNUM;
>> > +
>> > + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
>>
>> As the key of the hash, RELPATH should be duplicated into a pool with
>> sufficient lifetime.
>
> Good catch! Fixed in r1332508.
Thanks. For the same reason, you probably want to
s/apr_hash_copy/svn_prop_hash_dup/ over compat.c. The former only
duplicates the hash, not the keys or the contents, while the latter
will ensure the prophash has the same lifetime as the change it
belongs to.
-Hyrum
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Greg Stein <gs...@gmail.com>.
On Apr 30, 2012 9:38 PM, "Hyrum K Wright" <hy...@wandisco.com> wrote:
>...
> > +/* Insert a new change for RELPATH, or return an existing one. */
> > +static struct change_node *
> > +insert_change(const char *relpath,
> > + apr_hash_t *changes)
> > +{
> > + apr_pool_t *result_pool;
> > + struct change_node *change;
> > +
> > + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
> > + if (change != NULL)
> > + return change;
> > +
> > + result_pool = apr_hash_pool_get(changes);
> > +
> > + /* Return an empty change. Callers will tweak as needed. */
> > + change = apr_pcalloc(result_pool, sizeof(*change));
> > + change->changing = SVN_INVALID_REVNUM;
> > + change->deleting = SVN_INVALID_REVNUM;
> > +
> > + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
>
> As the key of the hash, RELPATH should be duplicated into a pool with
> sufficient lifetime.
Good catch! Fixed in r1332508.
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Greg Stein <gs...@gmail.com>.
On Apr 30, 2012 9:38 PM, "Hyrum K Wright" <hy...@wandisco.com> wrote:
>...
> > +/* Insert a new change for RELPATH, or return an existing one. */
> > +static struct change_node *
> > +insert_change(const char *relpath,
> > + apr_hash_t *changes)
> > +{
> > + apr_pool_t *result_pool;
> > + struct change_node *change;
> > +
> > + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
> > + if (change != NULL)
> > + return change;
> > +
> > + result_pool = apr_hash_pool_get(changes);
> > +
> > + /* Return an empty change. Callers will tweak as needed. */
> > + change = apr_pcalloc(result_pool, sizeof(*change));
> > + change->changing = SVN_INVALID_REVNUM;
> > + change->deleting = SVN_INVALID_REVNUM;
> > +
> > + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
>
> As the key of the hash, RELPATH should be duplicated into a pool with
> sufficient lifetime.
Good catch! Fixed in r1332508.
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Hyrum K Wright <hy...@wandisco.com>.
On Fri, Apr 27, 2012 at 8:50 PM, <gs...@apache.org> wrote:
> Author: gstein
> Date: Sat Apr 28 01:50:35 2012
> New Revision: 1331652
>
> URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
> Log:
> For the Ev2 shims:
>
> Revamp the Ev2/Ev1 shims by using struct change_node rather than the
> funky "operation" records and the build() function. Each Ev2 callback
> simply inserts a new change_node structure with some values in
> it. Later, we use the path_driver to apply these change_node
> structures to all modified paths.
>
> This obsoletes huge chunks of code; to be removed in a future revision.
>
> Test failures: log 38, merge 105.
>
> * subversion/libsvn_delta/compat.c:
> (process_actions): remove an incorrect assertion
> (struct editor_baton): add a CHANGES hash
> (insert_change): new helper function, similar to locate_change()
> (add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
> blocks for setting up change records
> (add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
> (alter_directory_cb, alter_file_cb): set up change records, noting
> that the record could have been created by an earlier copy/move.
> (copy_cb): set up change records. use the FETCH_KIND_FUNC callback
> to fetch kind information about the source (so we know what Ev1
> function to invoke for the destination)
> (move_cb): set up a change record for the source/deletion side, and
> the destination/copy side. use the FETCH_KIND_FUNC callback.
> (drive_ev1_props): helpful utility function to drive a series of
> single property changes (adds, modifies, deletes) to the Ev1
> editor. this helper also manages the special "unlock" mechanism
> (apply_change): apply all changes described in a change_node
> structure to a specified node
> (drive_changes): if any changes have been made (eg. start_edit_func
> was called an the root baton opened), then prepare a list of paths
> for the path_driver, and then run the sucker to make all the
> necessary edits. we have some special sneakiness to ensure the
> path_driver doesn't call open_root() a second time.
> (complete_cb, abort_cb): use drive_changes() rather than drive_root()
> (start_edit_func): leave a note about early-open of the root
> (do_unlock): record UNLOCK in the change_node. this will be handled
> by drive_ev1_props() later.
> (svn_delta__editor_from_delta): create the new CHANGES hash
>
> Modified:
> subversion/trunk/subversion/libsvn_delta/compat.c
>
> Modified: subversion/trunk/subversion/libsvn_delta/compat.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/compat.c?rev=1331652&r1=1331651&r2=1331652&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_delta/compat.c (original)
> +++ subversion/trunk/subversion/libsvn_delta/compat.c Sat Apr 28 01:50:35 2012
> @@ -434,8 +434,12 @@ process_actions(struct ev2_edit_baton *e
> if (props || contents)
> {
> /* Changes to properties or content should have indicated the revision
> - it was intending to change. */
> + it was intending to change.
> +
> + Oop. Not true. The node may be locally-added. */
> +#if 0
> SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(change->changing));
> +#endif
>
> if (kind == svn_kind_dir)
> SVN_ERR(svn_editor_alter_directory(eb->editor, repos_relpath,
> @@ -1042,10 +1046,38 @@ struct editor_baton
> const char *repos_root;
> const char *base_relpath;
>
> + /* REPOS_RELPATH -> struct change_node * */
> + apr_hash_t *changes;
> +
> apr_pool_t *edit_pool;
> };
>
>
> +/* Insert a new change for RELPATH, or return an existing one. */
> +static struct change_node *
> +insert_change(const char *relpath,
> + apr_hash_t *changes)
> +{
> + apr_pool_t *result_pool;
> + struct change_node *change;
> +
> + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
> + if (change != NULL)
> + return change;
> +
> + result_pool = apr_hash_pool_get(changes);
> +
> + /* Return an empty change. Callers will tweak as needed. */
> + change = apr_pcalloc(result_pool, sizeof(*change));
> + change->changing = SVN_INVALID_REVNUM;
> + change->deleting = SVN_INVALID_REVNUM;
> +
> + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
As the key of the hash, RELPATH should be duplicated into a pool with
sufficient lifetime.
>...
-Hyrum
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Re: svn commit: r1331652 - /subversion/trunk/subversion/libsvn_delta/compat.c
Posted by Hyrum K Wright <hy...@wandisco.com>.
On Fri, Apr 27, 2012 at 8:50 PM, <gs...@apache.org> wrote:
> Author: gstein
> Date: Sat Apr 28 01:50:35 2012
> New Revision: 1331652
>
> URL: http://svn.apache.org/viewvc?rev=1331652&view=rev
> Log:
> For the Ev2 shims:
>
> Revamp the Ev2/Ev1 shims by using struct change_node rather than the
> funky "operation" records and the build() function. Each Ev2 callback
> simply inserts a new change_node structure with some values in
> it. Later, we use the path_driver to apply these change_node
> structures to all modified paths.
>
> This obsoletes huge chunks of code; to be removed in a future revision.
>
> Test failures: log 38, merge 105.
>
> * subversion/libsvn_delta/compat.c:
> (process_actions): remove an incorrect assertion
> (struct editor_baton): add a CHANGES hash
> (insert_change): new helper function, similar to locate_change()
> (add_directory_cb, add_file_cb, add_absent_cb, delete_cb): add code
> blocks for setting up change records
> (add_symlink_cb): #if this whole thing out, and add SVN__NOT_IMPLEMENTED()
> (alter_directory_cb, alter_file_cb): set up change records, noting
> that the record could have been created by an earlier copy/move.
> (copy_cb): set up change records. use the FETCH_KIND_FUNC callback
> to fetch kind information about the source (so we know what Ev1
> function to invoke for the destination)
> (move_cb): set up a change record for the source/deletion side, and
> the destination/copy side. use the FETCH_KIND_FUNC callback.
> (drive_ev1_props): helpful utility function to drive a series of
> single property changes (adds, modifies, deletes) to the Ev1
> editor. this helper also manages the special "unlock" mechanism
> (apply_change): apply all changes described in a change_node
> structure to a specified node
> (drive_changes): if any changes have been made (eg. start_edit_func
> was called an the root baton opened), then prepare a list of paths
> for the path_driver, and then run the sucker to make all the
> necessary edits. we have some special sneakiness to ensure the
> path_driver doesn't call open_root() a second time.
> (complete_cb, abort_cb): use drive_changes() rather than drive_root()
> (start_edit_func): leave a note about early-open of the root
> (do_unlock): record UNLOCK in the change_node. this will be handled
> by drive_ev1_props() later.
> (svn_delta__editor_from_delta): create the new CHANGES hash
>
> Modified:
> subversion/trunk/subversion/libsvn_delta/compat.c
>
> Modified: subversion/trunk/subversion/libsvn_delta/compat.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/compat.c?rev=1331652&r1=1331651&r2=1331652&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_delta/compat.c (original)
> +++ subversion/trunk/subversion/libsvn_delta/compat.c Sat Apr 28 01:50:35 2012
> @@ -434,8 +434,12 @@ process_actions(struct ev2_edit_baton *e
> if (props || contents)
> {
> /* Changes to properties or content should have indicated the revision
> - it was intending to change. */
> + it was intending to change.
> +
> + Oop. Not true. The node may be locally-added. */
> +#if 0
> SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(change->changing));
> +#endif
>
> if (kind == svn_kind_dir)
> SVN_ERR(svn_editor_alter_directory(eb->editor, repos_relpath,
> @@ -1042,10 +1046,38 @@ struct editor_baton
> const char *repos_root;
> const char *base_relpath;
>
> + /* REPOS_RELPATH -> struct change_node * */
> + apr_hash_t *changes;
> +
> apr_pool_t *edit_pool;
> };
>
>
> +/* Insert a new change for RELPATH, or return an existing one. */
> +static struct change_node *
> +insert_change(const char *relpath,
> + apr_hash_t *changes)
> +{
> + apr_pool_t *result_pool;
> + struct change_node *change;
> +
> + change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
> + if (change != NULL)
> + return change;
> +
> + result_pool = apr_hash_pool_get(changes);
> +
> + /* Return an empty change. Callers will tweak as needed. */
> + change = apr_pcalloc(result_pool, sizeof(*change));
> + change->changing = SVN_INVALID_REVNUM;
> + change->deleting = SVN_INVALID_REVNUM;
> +
> + apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
As the key of the hash, RELPATH should be duplicated into a pool with
sufficient lifetime.
>...
-Hyrum
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/