Only a couple of nit-pick comments.
Generally, since there is already discussion in the file itself, I'd
support committing additional discussion directly, and then discussing it
on the mailing list if needed.
-Hyrum
On Thu, Nov 3, 2011 at 1:10 PM, Julian Foad <julian.foad_at_wandisco.com>wrote:
> Here, in the form of a patch, are many suggestions and queries I've
> made on Ev2. I'm not intimately familiar with the design and goals of
> it, I'm just responding to how it's currently written up in the header
> file, with some memory of past discussions. Discussion welcomed.
>
> [[[
> Index: subversion/include/svn_editor.h
> ===================================================================
> --- subversion/include/svn_editor.h (revision 1197094)
> +++ subversion/include/svn_editor.h (working copy)
> @@ -177,18 +177,25 @@
> * \n\n
> * Just before each callback invocation is carried out, the @a
> cancel_func
> * that was passed to svn_editor_create() is invoked to poll any
> * external reasons to cancel the sequence of operations. Unless it
> * overrides the cancellation (denoted by #SVN_ERR_CANCELLED), the
> driver
> * aborts the transmission by invoking the svn_editor_abort() callback.
> * Exceptions to this are calls to svn_editor_complete() and
> * svn_editor_abort(), which cannot be canceled externally.
> *
> + * ### JAF: It should check for cancellation before 'complete'.
> + * Imagine the user runs 'svn commit large-new-file' and then
> + * tries to cancel it, and imagine svn_editor_add() does not
> + * internally respond to cancellation. If the driver then calls
> + * 'complete' without intercepting the cancellation, the user
> + * would not be happy to see that commit being completed.
> + *
> * - @b Receive: While the driver invokes operations upon the editor, the
> * receiver finds its callback functions called with the information
> * to operate on its tree. Each actual callback function receives those
> * arguments that the driver passed to the "driving" functions, plus
> these:
> * - @a baton: This is the @a editor_baton pointer originally passed to
> * svn_editor_create(). It may be freely used by the callback
> * implementation to store information across all callbacks.
> * - @a scratch_pool: This temporary pool is cleared directly after
> * each callback returns. See "Pool Usage".
> @@ -203,76 +210,111 @@
> *
> * <h3>Driving Order Restrictions</h3>
> * In order to reduce complexity of callback receivers, the editor
> callbacks
> * must be driven in adherence to these rules:
> *
> * - svn_editor_add_directory() -- Another svn_editor_add_*() call must
> * follow for each child mentioned in the @a children argument of any
> * svn_editor_add_directory() call.
> *
> + * ### JAF: ... must follow at any time after the parent
> add_directory(),
> + * and not before it.
> + *
> * - svn_editor_set_props()
> * - The @a complete argument must be TRUE if no more calls will follow
> on
> * the same path. @a complete must always be TRUE for directories.
> * - If @a complete is FALSE, and:
> * - if @a relpath is a file, this must (at some point) be followed by
> * an svn_editor_set_text() call on the same path.
> * - if @a relpath is a symlink, this must (at some point) be followed
> by
> * an svn_editor_set_target() call on the same path.
> *
> * - svn_editor_set_text() and svn_editor_set_target() must always occur
> * @b after an svn_editor_set_props() call on the same path, if any.
> *
> * In other words, if there are two calls coming in on the same path, the
> * first of them has to be svn_editor_set_props().
> *
> + * ### JAF: The set_* functions treat the properties of a node as
> + * separate from the node's text or symlink target, whereas the
> + * add_* functions treat the properties as an integral part of each
> + * kind of node. This seems like a needless difference. It would make
> + * sense for set_text() to take the properties with the text, and let
> + * the implementation worry about whether the props and/or the text
> + * have actually changed (as well as how to transmit the changes
> + * most efficiently). For symlinks, include the properties with the
> + * 'set target' call (rename to 'set symlink') and for directories
> + * introduce a 'set directory' function, and remove the set_props()
> + * function. This would eliminate the exception in the "Once Rule".
> + *
> * - Other than the above two pairs of linked operations, a path should
> * never be referenced more than once by the add_* and set_* and the
> * delete operations (the "Once Rule"). The source path of a copy (and
> * its children, if a directory) may be copied many times, and are
> * otherwise subject to the Once Rule. The destination path of a copy
> * or move may have set_* operations applied, but not add_* or delete.
> * If the destination path of a copy or move is a directory, then its
> * children are subject to the Once Rule. The source path of a move
> * (and its child paths) may be referenced in add_*, or as the
> * destination of a copy (where these new, copied nodes are subject to
> * the Once Rule).
> *
> * - The ancestor of an added or modified node may not be deleted. The
> * ancestor may not be moved (instead: perform the move, *then* the
> edits).
> + *
> + * ### JAF: Ancestor == parent dir?
> + *
> + * ### JAF: The ancestor of a node that is modified or added or
> copied-here
> + * or moved-here ...?
> + *
> + * ### JAF: The ancestor of ... [can | may not?] be copied or moved.
> *
> * - svn_editor_delete() must not be used to replace a path -- i.e.
> * svn_editor_delete() must not be followed by an svn_editor_add_*() on
> * the same path, nor by an svn_editor_copy() or svn_editor_move() with
> * the same path as the copy/move target.
> + *
> + * ### JAF: Nor followed by set_*().
> + *
> + * ### JAF: Nor followed by copy() or move() with the same path as the
> + * copy/move source?
> *
> * Instead of a prior delete call, the add/copy/move callbacks should be
> * called with the @a replaces_rev argument set to the revision number of
> * the node at this path that is being replaced. Note that the path and
> * revision number are the key to finding any other information about the
> * replaced node, like node kind, etc.
> * @todo say which function(s) to use.
> + *
> + * ### JAF: Can we have a way to refer to replacing a node in a tree that
> + * is not a committed revision and so doesn't have a revision number?
> + * This seems to be the only place where the editor definition
> requires
> + * that a target node is a (copy of a) committed repository node.
> *
> - * - svn_editor_delete() must not be used to move a path -- i.e.
> - * svn_editor_delete() must not delete the source path of a previous
> + * - svn_editor_delete() should not be used to move a path -- i.e.
> + * svn_editor_delete() should not delete the source path of a previous
>
These should be left as-is, per RFC 2119.
> * svn_editor_copy() call. Instead, svn_editor_move() must be used.
> * Note: if the desired semantics is one (or more) copies, followed
> * by a delete... that is fine. It is simply that svn_editor_move()
> * should be used to describe a semantic move.
> *
> * - One of svn_editor_complete() or svn_editor_abort() must be called
> * exactly once, which must be the final call the driver invokes.
> * Invoking svn_editor_complete() must imply that the set of changes has
> * been transmitted completely and without errors, and invoking
> * svn_editor_abort() must imply that the transformation was not
> completed
> * successfully.
> *
> * - If any callback invocation returns with an error, the driver must
> * invoke svn_editor_abort() and stop transmitting operations.
> + *
> + * - ### JAF: Some restriction analogous to the receiver's "All callbacks
> + * must complete their handling of a path before they return ..."?
> * \n\n
> *
> * <h3>Receiving Restrictions</h3>
> * All callbacks must complete their handling of a path before they
> * return, except for the following pairs, where a change must be completed
> * when receiving the second callback in each pair:
> * - svn_editor_set_props() (if @a complete is FALSE) and
> * svn_editor_set_text() (if the node is a file)
> * - svn_editor_set_props() (if @a complete is FALSE) and
> @@ -328,25 +370,45 @@
> * calling any of the driving functions (e.g. svn_editor_add_directory()).
> * As with any other error, the driver must then invoke svn_editor_abort()
> * and abort the transformation sequence. See #svn_cancel_func_t.
> *
> * The @a cancel_baton argument to svn_editor_create() is passed
> * unchanged to each poll of @a cancel_func.
> *
> * The cancellation function and baton are typically provided by the client
> * context.
> + *
> + * ### JAF: Bring the section on cancellation under the Life-Cycle heading
> + * down to here and combine it.
> *
> *
> * @todo ### TODO anything missing? -- allow text and prop change to follow
> - * a move or copy. -- set_text() vs. apply_text_delta()? -- If a
> + * a move or copy. -- set_text() vs. apply_text_delta()?
> + *
> + * ### JAF: Those two seem to be done already.
> + *
> + * -- If a
> * set_props/set_text/set_target/copy/move/delete in a merge source is
> * applied to a different branch, which side will REVISION arguments
> reflect
> * and is there still a problem?
> + *
> + * ### JAF: The 'revision' argument will always refer to the 'before'
> + * state of the source node that the editor is editing. The receiver
> + * must know about this source node to make sense of the edit. If
> + * the receiver is merging the source-node edits into some other
> + * node on a different target branch, the editor knows nothing about
> + * that other node (which may not even have a revision number if
> + * it's a working version that's been modified already by some
> + * previous merge or user intervention).
> + *
> + * ### JAF: As well as the text checksum for files, consider adding an
> + * (optional?) checksum for the full content of every node kind --
> + * text with props, symlink with props, dir with list of children.
> *
> * @since New in 1.8.
> */
> typedef struct svn_editor_t svn_editor_t;
>
>
> /** These function types define the callback functions a tree delta
> consumer
> * implements.
> *
> @@ -698,57 +760,51 @@
> *
> * Create a new directory at @a relpath. The immediate parent of @a relpath
> * is expected to exist.
> *
> * Set the properties of the new directory to @a props, which is an
> * apr_hash_t holding key-value pairs. Each key is a const char* of a
> * property name, each value is a const svn_string_t*. If no properties are
> * being set on the new directory, @a props must be NULL.
> *
> - * If this add is expected to replace a previously existing file or
> - * directory at @a relpath, the revision number of the node to be replaced
> + * If this add is expected to replace a previously existing node
>
Use the more specific "directory" rather than "node". (This is a doctoring
which only applies to directories.)
> + * at @a relpath, the revision number of the node to be replaced
> * must be given in @a replaces_rev. Otherwise, @a replaces_rev must be
> * SVN_INVALID_REVNUM. Note: it is not allowed to call a "delete" followed
> * by an "add" on the same path. Instead, an "add" with @a replaces_rev set
> * accordingly MUST be used.
> *
> * A complete listing of the immediate children of @a relpath that will be
> * added subsequently is given in @a children. @a children is an array of
> * const char*s, each giving the basename of an immediate child.
> *
> * For all restrictions on driving the editor, see #svn_editor_t.
> */
> svn_error_t *
> svn_editor_add_directory(svn_editor_t *editor,
> const char *relpath,
> const apr_array_header_t *children,
> apr_hash_t *props,
> svn_revnum_t replaces_rev);
> +/* ### JAF: Let's keep the 'relpath' and 'replaces_rev' params together,
> + * like they are in the delete/copy/move callbacks, because
> + * logically they're tightly related. Also in other add_*(). */
>
> /** Drive @a editor's #svn_editor_cb_add_file_t callback.
> *
> * Create a new file at @a relpath. The immediate parent of @a relpath
> * is expected to exist.
> *
> * The file's contents are specified in @a contents which has a checksum
> * matching @a checksum.
> *
> - * Set the properties of the new file to @a props, which is an
> - * apr_hash_t holding key-value pairs. Each key is a const char* of a
> - * property name, each value is a const svn_string_t*. If no properties
> are
> - * being set on the new file, @a props must be NULL.
> - *
> - * If this add is expected to replace a previously existing file or
> - * directory at @a relpath, the revision number of the node to be replaced
> - * must be given in @a replaces_rev. Otherwise, @a replaces_rev must be
> - * SVN_INVALID_REVNUM. Note: it is not allowed to call a "delete"
> followed
> - * by an "add" on the same path. Instead, an "add" with @a replaces_rev
> set
> - * accordingly MUST be used.
> + * For descriptions of @a props and @a replaces_rev, see
> + * svn_editor_add_file().
> *
> * For all restrictions on driving the editor, see #svn_editor_t.
> * @since New in 1.8.
> */
> svn_error_t *
> svn_editor_add_file(svn_editor_t *editor,
> const char *relpath,
> const svn_checksum_t *checksum,
> svn_stream_t *contents,
> @@ -772,18 +828,19 @@
> const char *target,
> apr_hash_t *props,
> svn_revnum_t replaces_rev);
>
> /** Drive @a editor's #svn_editor_cb_add_absent_t callback.
> *
> * Create an "absent" node of kind @a kind at @a relpath. The immediate
> * parent of @a relpath is expected to exist.
> * ### TODO @todo explain "absent".
> + * ### JAF: What are the allowed values of 'kind'?
> *
> * For a description of @a replaces_rev, see svn_editor_add_file().
> *
> * For all restrictions on driving the editor, see #svn_editor_t.
> * @since New in 1.8.
> */
> svn_error_t *
> svn_editor_add_absent(svn_editor_t *editor,
> const char *relpath,
> @@ -794,18 +851,20 @@
> *
> * Set or change properties on the existing node at @a relpath. This
> * function sends *all* properties, both existing and changes.
> * ### TODO @todo What is REVISION for?
> * ### HKW: This is puzzling to me as well...
> * ###
> * ### what about "entry props"? will these still be handled via
> * ### the general prop function?
> *
> + * For a description of @a props, see svn_editor_add_file().
> + *
> * @a complete must be FALSE if and only if
> * - @a relpath is a file and an svn_editor_set_text() call will follow on
> * the same path, or
> * - @a relpath is a symbolic link and an svn_editor_set_target() call will
> * follow on the same path.
> *
> * For all restrictions on driving the editor, see #svn_editor_t.
> * @since New in 1.8.
> */
> @@ -815,18 +874,47 @@
> svn_revnum_t revision,
> apr_hash_t *props,
> svn_boolean_t complete);
>
> /** Drive @a editor's #svn_editor_cb_set_text_t callback.
> *
> * Set/change the text content of a file at @a relpath to @a contents
> * with checksum @a checksum.
> * ### TODO @todo Does this send the *complete* content, always?
> + * ### JAF: I think the idea is that 'contents' is the new full text and,
> + * if wanted, the driver and receiver implementations should diff and
> + * patch (respectively) it against the old full text.
> + *
> + * ### JAF: This may be inefficient for an implementation that already
> + * has a diff available but doesn't have a full text available
> + * (perhaps neither the 'before' nor the 'after' full text). We
> + * should consider providing an alternative driver-side API so
> + * that the driver can choose to bypass this full-text phase and
> + * send the new text directly in any representation agreed with
> + * the receiver, including as a diff against the old. On the
> + * receiver side the same consideration applies.
>
Please, please, please, please, no secret backdoors! Let's get this
implementation figured out, and then worry about potential optimizations.
> + *
> + * ### JAF: For the driver: @a contents is a readable stream. The editor
> + * implementation may pull text from it as required, and will then
> + * close it before returning. The editor [### need not | will]
> + * pull all the text from the stream before closing it.
> + *
> + * ### JAF: For the receiver: @a contents is a readable stream. The
> + * receiver may pull text from it as required, and will then
> + * close it before returning. The receiver [### need not | will]
> + * pull all the text from the stream before closing it.
> + *
> + * ### JAF: Is it permissible for the text change to be a no-op? The
> + * driver may wish to avoid doing so for efficiency if it knows,
> + * but I'd say we should not forbid it. Either way we should
> + * consider how to be consistent in this regard across all the
> + * whole editor.
>
No-op text changes are permissible.
> + *
> * ### TODO @todo What is REVISION for?
> *
> * For all restrictions on driving the editor, see #svn_editor_t.
> * @since New in 1.8.
> */
> svn_error_t *
> svn_editor_set_text(svn_editor_t *editor,
> const char *relpath,
> svn_revnum_t revision,
> ]]]
>
> - Julian
>
--
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/
Received on 2011-11-03 19:38:12 CET