You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2014/06/30 16:09:16 UTC

svn commit: r1606748 [2/2] - in /subversion/branches/move-tracking-2/subversion: include/private/svn_editor3.h libsvn_delta/editor3.c

Copied: subversion/branches/move-tracking-2/subversion/libsvn_delta/editor3.c (from r1606692, subversion/branches/move-tracking-2/subversion/libsvn_delta/editor.c)
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/editor3.c?p2=subversion/branches/move-tracking-2/subversion/libsvn_delta/editor3.c&p1=subversion/branches/move-tracking-2/subversion/libsvn_delta/editor.c&r1=1606692&r2=1606748&rev=1606748&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_delta/editor3.c Mon Jun 30 14:09:16 2014
@@ -28,28 +28,17 @@
 #include "svn_pools.h"
 #include "svn_dirent_uri.h"
 
-#include "private/svn_editor.h"
+#include "private/svn_editor3.h"
 
 #ifdef SVN_DEBUG
 /* This enables runtime checks of the editor API constraints.  This may
    introduce additional memory and runtime overhead, and should not be used
-   in production builds.
-
-   ### Remove before release?
-
-   ### Disabled for now.  If I call svn_editor_alter_directory(A) then
-       svn_editor_add_file(A/f) the latter fails on SHOULD_ALLOW_ADD.
-       If I modify svn_editor_alter_directory to MARK_ALLOW_ADD(child)
-       then if I call svn_editor_alter_directory(A) followed by
-       svn_editor_alter_directory(A/B/C) the latter fails on
-       VERIFY_PARENT_MAY_EXIST. */
-#if 0
+   in production builds. */
 #define ENABLE_ORDERING_CHECK
 #endif
-#endif
 
 
-struct svn_editor_t
+struct svn_editor3_t
 {
   void *baton;
 
@@ -57,20 +46,15 @@ struct svn_editor_t
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
 
-  /* Our callback functions match that of the set-many structure, so
-     just use that.  */
-  svn_editor_cb_many_t funcs;
+  /* The callback functions.  */
+  svn_editor3_cb_funcs_t funcs;
 
   /* This pool is used as the scratch_pool for all callbacks.  */
   apr_pool_t *scratch_pool;
 
 #ifdef ENABLE_ORDERING_CHECK
   svn_boolean_t within_callback;
-
-  apr_hash_t *pending_incomplete_children;
-  apr_hash_t *completed_nodes;
   svn_boolean_t finished;
-
   apr_pool_t *state_pool;
 #endif
 };
@@ -80,201 +64,45 @@ struct svn_editor_t
 
 #define START_CALLBACK(editor)                       \
   do {                                               \
-    svn_editor_t *editor__tmp_e = (editor);          \
+    svn_editor3_t *editor__tmp_e = (editor);          \
     SVN_ERR_ASSERT(!editor__tmp_e->within_callback); \
     editor__tmp_e->within_callback = TRUE;           \
   } while (0)
 #define END_CALLBACK(editor) ((editor)->within_callback = FALSE)
 
-/* Marker to indicate no further changes are allowed on this node.  */
-static const int marker_done = 0;
-#define MARKER_DONE (&marker_done)
-
-/* Marker indicating that add_* may be called for this path, or that it
-   can be the destination of a copy or move. For copy/move, the path
-   will switch to MARKER_ALLOW_ALTER, to enable further tweaks.  */
-static const int marker_allow_add = 0;
-#define MARKER_ALLOW_ADD (&marker_allow_add)
-
-/* Marker indicating that alter_* may be called for this path.  */
-static const int marker_allow_alter = 0;
-#define MARKER_ALLOW_ALTER (&marker_allow_alter)
-
-/* Just like MARKER_DONE, but also indicates that the node was created
-   via add_directory(). This allows us to verify that the CHILDREN param
-   was comprehensive.  */
-static const int marker_added_dir = 0;
-#define MARKER_ADDED_DIR (&marker_added_dir)
-
 #define MARK_FINISHED(editor) ((editor)->finished = TRUE)
 #define SHOULD_NOT_BE_FINISHED(editor)  SVN_ERR_ASSERT(!(editor)->finished)
 
-#define CLEAR_INCOMPLETE(editor, relpath) \
-  svn_hash_sets((editor)->pending_incomplete_children, relpath, NULL);
-
-#define MARK_RELPATH(editor, relpath, value) \
-  svn_hash_sets((editor)->completed_nodes, \
-                apr_pstrdup((editor)->state_pool, relpath), value)
-
-#define MARK_COMPLETED(editor, relpath) \
-  MARK_RELPATH(editor, relpath, MARKER_DONE)
-#define SHOULD_NOT_BE_COMPLETED(editor, relpath) \
-  SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, relpath) == NULL)
-
-#define MARK_ALLOW_ADD(editor, relpath) \
-  MARK_RELPATH(editor, relpath, MARKER_ALLOW_ADD)
-#define SHOULD_ALLOW_ADD(editor, relpath) \
-  SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ADD, NULL))
-
-#define MARK_ALLOW_ALTER(editor, relpath) \
-  MARK_RELPATH(editor, relpath, MARKER_ALLOW_ALTER)
-#define SHOULD_ALLOW_ALTER(editor, relpath) \
-  SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ALTER, NULL))
-
-#define MARK_ADDED_DIR(editor, relpath) \
-  MARK_RELPATH(editor, relpath, MARKER_ADDED_DIR)
-#define CHECK_UNKNOWN_CHILD(editor, relpath) \
-  SVN_ERR_ASSERT(check_unknown_child(editor, relpath))
-
-/* When a child is changed in some way, mark the parent directory as needing
-   to be "stable" (no future structural changes). IOW, only allow "alter" on
-   the parent. Prevents parent-add/delete/move after any child operation.  */
-#define MARK_PARENT_STABLE(editor, relpath) \
-  mark_parent_stable(editor, relpath)
-
-/* If the parent is MARKER_ALLOW_ADD, then it has been moved-away, and we
-   know it does not exist. All other cases: it might exist.  */
-#define VERIFY_PARENT_MAY_EXIST(editor, relpath) \
-  SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, \
-                               svn_relpath_dirname(relpath, \
-                                                   (editor)->scratch_pool)) \
-                 != MARKER_ALLOW_ADD)
-
-/* If the parent is MARKER_ADDED_DIR, then we should not be deleting
-   children(*). If the parent is MARKER_ALLOW_ADD, then it has been
-   moved-away, so children cannot exist. That leaves MARKER_DONE,
-   MARKER_ALLOW_ALTER, and NULL as possible values. Just assert that
-   we didn't get either of the bad ones.
-
-   (*) if the child as added via add_*(), then it would have been marked
-   as completed and delete/move-away already test against completed nodes.
-   This test is to beware of trying to delete "children" that are not
-   actually (and can't possibly be) present.  */
-#define CHILD_DELETIONS_ALLOWED(editor, relpath) \
-  SVN_ERR_ASSERT(!allow_either(editor, \
-                               svn_relpath_dirname(relpath, \
-                                                   (editor)->scratch_pool), \
-                               MARKER_ADDED_DIR, MARKER_ALLOW_ADD))
-
-static svn_boolean_t
-allow_either(const svn_editor_t *editor,
-             const char *relpath,
-             const void *marker1,
-             const void *marker2)
-{
-  void *value = svn_hash_gets(editor->completed_nodes, relpath);
-  return value == marker1 || value == marker2;
-}
-
-static svn_boolean_t
-check_unknown_child(const svn_editor_t *editor,
-                    const char *relpath)
-{
-  const char *parent;
-
-  /* If we already know about the new child, then exit early.  */
-  if (svn_hash_gets(editor->pending_incomplete_children, relpath) != NULL)
-    return TRUE;
-
-  parent = svn_relpath_dirname(relpath, editor->scratch_pool);
-
-  /* Was this parent created via svn_editor_add_directory() ?  */
-  if (svn_hash_gets(editor->completed_nodes, parent)
-      == MARKER_ADDED_DIR)
-    {
-      /* Whoops. This child should have been listed in that add call,
-         and placed into ->pending_incomplete_children.  */
-      return FALSE;
-    }
-
-  /* The parent was not added in this drive.  */
-  return TRUE;
-}
-
-static void
-mark_parent_stable(const svn_editor_t *editor,
-                   const char *relpath)
-{
-  const char *parent = svn_relpath_dirname(relpath, editor->scratch_pool);
-  const void *marker = svn_hash_gets(editor->completed_nodes, parent);
-
-  /* If RELPATH has already been marked (to disallow adds, or that it
-     has been fully-completed), then do nothing.  */
-  if (marker == MARKER_ALLOW_ALTER
-      || marker == MARKER_DONE
-      || marker == MARKER_ADDED_DIR)
-    return;
-
-  /* If the marker is MARKER_ALLOW_ADD, then that means the parent was
-     moved away. There is no way to work on a child. That should have
-     been tested before we got here by VERIFY_PARENT_MAY_EXIST().  */
-  SVN_ERR_ASSERT_NO_RETURN(marker != MARKER_ALLOW_ADD);
-
-  /* MARKER is NULL. Upgrade it to MARKER_ALLOW_ALTER.  */
-  MARK_RELPATH(editor, parent, MARKER_ALLOW_ALTER);
-}
-
 #else
 
-/* Be wary with the definition of these macros so that we don't
-   end up with "statement with no effect" warnings. Obviously, this
-   depends upon particular usage, which is easy to verify.  */
-
 #define START_CALLBACK(editor)  /* empty */
 #define END_CALLBACK(editor)  /* empty */
 
 #define MARK_FINISHED(editor)  /* empty */
 #define SHOULD_NOT_BE_FINISHED(editor)  /* empty */
 
-#define CLEAR_INCOMPLETE(editor, relpath)  /* empty */
-
-#define MARK_COMPLETED(editor, relpath)  /* empty */
-#define SHOULD_NOT_BE_COMPLETED(editor, relpath)  /* empty */
-
-#define MARK_ALLOW_ADD(editor, relpath)  /* empty */
-#define SHOULD_ALLOW_ADD(editor, relpath)  /* empty */
-
-#define MARK_ALLOW_ALTER(editor, relpath)  /* empty */
-#define SHOULD_ALLOW_ALTER(editor, relpath)  /* empty */
-
-#define MARK_ADDED_DIR(editor, relpath)  /* empty */
-#define CHECK_UNKNOWN_CHILD(editor, relpath)  /* empty */
-
-#define MARK_PARENT_STABLE(editor, relpath)  /* empty */
-#define VERIFY_PARENT_MAY_EXIST(editor, relpath)  /* empty */
-#define CHILD_DELETIONS_ALLOWED(editor, relpath)  /* empty */
-
 #endif /* ENABLE_ORDERING_CHECK */
 
 
 svn_error_t *
-svn_editor_create(svn_editor_t **editor,
-                  void *editor_baton,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool)
+svn_editor3_create(svn_editor3_t **editor,
+                   const svn_editor3_cb_funcs_t *editor_funcs,
+                   void *editor_baton,
+                   svn_cancel_func_t cancel_func,
+                   void *cancel_baton,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
 {
   *editor = apr_pcalloc(result_pool, sizeof(**editor));
 
+  (*editor)->funcs = *editor_funcs;
   (*editor)->baton = editor_baton;
   (*editor)->cancel_func = cancel_func;
   (*editor)->cancel_baton = cancel_baton;
   (*editor)->scratch_pool = svn_pool_create(result_pool);
 
 #ifdef ENABLE_ORDERING_CHECK
-  (*editor)->pending_incomplete_children = apr_hash_make(result_pool);
-  (*editor)->completed_nodes = apr_hash_make(result_pool);
+  (*editor)->within_callback = FALSE;
   (*editor)->finished = FALSE;
   (*editor)->state_pool = result_pool;
 #endif
@@ -284,581 +112,344 @@ svn_editor_create(svn_editor_t **editor,
 
 
 void *
-svn_editor_get_baton(const svn_editor_t *editor)
+svn_editor3_get_baton(const svn_editor3_t *editor)
 {
   return editor->baton;
 }
 
 
-svn_error_t *
-svn_editor_setcb_add_directory(svn_editor_t *editor,
-                               svn_editor_cb_add_directory_t callback,
-                               apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_add_directory = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_add_file(svn_editor_t *editor,
-                          svn_editor_cb_add_file_t callback,
-                          apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_add_file = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_add_symlink(svn_editor_t *editor,
-                             svn_editor_cb_add_symlink_t callback,
-                             apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_add_symlink = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_add_absent(svn_editor_t *editor,
-                            svn_editor_cb_add_absent_t callback,
-                            apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_add_absent = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_alter_directory(svn_editor_t *editor,
-                                 svn_editor_cb_alter_directory_t callback,
-                                 apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_alter_directory = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_alter_file(svn_editor_t *editor,
-                            svn_editor_cb_alter_file_t callback,
-                            apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_alter_file = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_alter_symlink(svn_editor_t *editor,
-                               svn_editor_cb_alter_symlink_t callback,
-                               apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_alter_symlink = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_delete(svn_editor_t *editor,
-                        svn_editor_cb_delete_t callback,
-                        apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_delete = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_copy(svn_editor_t *editor,
-                      svn_editor_cb_copy_t callback,
-                      apr_pool_t *scratch_pool)
+static svn_error_t *
+check_cancel(svn_editor3_t *editor)
 {
-  editor->funcs.cb_copy = callback;
-  return SVN_NO_ERROR;
-}
+  svn_error_t *err = NULL;
 
+  if (editor->cancel_func)
+    {
+      START_CALLBACK(editor);
+      err = editor->cancel_func(editor->cancel_baton);
+      END_CALLBACK(editor);
+    }
 
-svn_error_t *
-svn_editor_setcb_move(svn_editor_t *editor,
-                      svn_editor_cb_move_t callback,
-                      apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_move = callback;
-  return SVN_NO_ERROR;
+  return svn_error_trace(err);
 }
 
 
-svn_error_t *
-svn_editor_setcb_complete(svn_editor_t *editor,
-                          svn_editor_cb_complete_t callback,
-                          apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_complete = callback;
-  return SVN_NO_ERROR;
-}
-
+/*
+ * ===================================================================
+ * Editor for Commit from WC, with Incremental Path-Based Tree Changes
+ * ===================================================================
+ */
 
 svn_error_t *
-svn_editor_setcb_abort(svn_editor_t *editor,
-                       svn_editor_cb_abort_t callback,
-                       apr_pool_t *scratch_pool)
+svn_editor3_mk(svn_editor3_t *editor,
+               svn_node_kind_t new_kind,
+               pathrev_t parent_loc,
+               const char *new_name)
 {
-  editor->funcs.cb_abort = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_editor_setcb_many(svn_editor_t *editor,
-                      const svn_editor_cb_many_t *many,
-                      apr_pool_t *scratch_pool)
-{
-#define COPY_CALLBACK(NAME) if (many->NAME) editor->funcs.NAME = many->NAME
-
-  COPY_CALLBACK(cb_add_directory);
-  COPY_CALLBACK(cb_add_file);
-  COPY_CALLBACK(cb_add_symlink);
-  COPY_CALLBACK(cb_add_absent);
-  COPY_CALLBACK(cb_alter_directory);
-  COPY_CALLBACK(cb_alter_file);
-  COPY_CALLBACK(cb_alter_symlink);
-  COPY_CALLBACK(cb_delete);
-  COPY_CALLBACK(cb_copy);
-  COPY_CALLBACK(cb_move);
-  COPY_CALLBACK(cb_complete);
-  COPY_CALLBACK(cb_abort);
-
-#undef COPY_CALLBACK
-
-  return SVN_NO_ERROR;
-}
+  svn_error_t *err = SVN_NO_ERROR;
 
+  /* SVN_ERR_ASSERT(...); */
 
-static svn_error_t *
-check_cancel(svn_editor_t *editor)
-{
-  svn_error_t *err = NULL;
+  SVN_ERR(check_cancel(editor));
 
-  if (editor->cancel_func)
+  if (editor->funcs.cb_mk)
     {
       START_CALLBACK(editor);
-      err = editor->cancel_func(editor->cancel_baton);
+      err = editor->funcs.cb_mk(editor->baton,
+                                new_kind, parent_loc, new_name,
+                                editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
+  svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 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)
+svn_editor3_cp(svn_editor3_t *editor,
+               pathrev_t from_loc,
+               pathrev_t parent_loc,
+               const char *new_name)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT(children != NULL);
-  SVN_ERR_ASSERT(props != NULL);
-  /* ### validate children are just basenames?  */
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ADD(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
-  CHECK_UNKNOWN_CHILD(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_add_directory)
+  if (editor->funcs.cb_cp)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
-                                           props, replaces_rev,
-                                           editor->scratch_pool);
+      err = editor->funcs.cb_cp(editor->baton,
+                                from_loc, parent_loc, new_name,
+                                editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_ADDED_DIR(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
-  CLEAR_INCOMPLETE(editor, relpath);
-
-#ifdef ENABLE_ORDERING_CHECK
-  {
-    int i;
-    for (i = 0; i < children->nelts; i++)
-      {
-        const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
-        const char *child = svn_relpath_join(relpath, child_basename,
-                                             editor->state_pool);
-
-        svn_hash_sets(editor->pending_incomplete_children, child, "");
-      }
-  }
-#endif
-
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_add_file(svn_editor_t *editor,
-                    const char *relpath,
-                    const svn_checksum_t *checksum,
-                    svn_stream_t *contents,
-                    apr_hash_t *props,
-                    svn_revnum_t replaces_rev)
+svn_editor3_mv(svn_editor3_t *editor,
+               pathrev_t from_loc,
+               pathrev_t new_parent_loc,
+               const char *new_name)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT(checksum != NULL
-                    && checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
-  SVN_ERR_ASSERT(contents != NULL);
-  SVN_ERR_ASSERT(props != NULL);
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ADD(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
-  CHECK_UNKNOWN_CHILD(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_add_file)
+  if (editor->funcs.cb_mv)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_add_file(editor->baton, relpath,
-                                      checksum, contents, props,
-                                      replaces_rev, editor->scratch_pool);
+      err = editor->funcs.cb_mv(editor->baton,
+                                from_loc, new_parent_loc, new_name,
+                                editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
-  CLEAR_INCOMPLETE(editor, relpath);
-
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_add_symlink(svn_editor_t *editor,
-                       const char *relpath,
-                       const char *target,
-                       apr_hash_t *props,
-                       svn_revnum_t replaces_rev)
+svn_editor3_res(svn_editor3_t *editor,
+                pathrev_t from_loc,
+                pathrev_t parent_loc,
+                const char *new_name)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT(props != NULL);
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ADD(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
-  CHECK_UNKNOWN_CHILD(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_add_symlink)
+  if (editor->funcs.cb_res)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_add_symlink(editor->baton, relpath, target, props,
-                                         replaces_rev, editor->scratch_pool);
+      err = editor->funcs.cb_res(editor->baton,
+                                 from_loc, parent_loc, new_name,
+                                 editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
-  CLEAR_INCOMPLETE(editor, relpath);
-
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_add_absent(svn_editor_t *editor,
-                      const char *relpath,
-                      svn_node_kind_t kind,
-                      svn_revnum_t replaces_rev)
+svn_editor3_rm(svn_editor3_t *editor,
+               pathrev_t loc)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ADD(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
-  CHECK_UNKNOWN_CHILD(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_add_absent)
+  if (editor->funcs.cb_rm)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_add_absent(editor->baton, relpath, kind,
-                                        replaces_rev, editor->scratch_pool);
+      err = editor->funcs.cb_rm(editor->baton,
+                                loc,
+                                editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
-  CLEAR_INCOMPLETE(editor, relpath);
-
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_alter_directory(svn_editor_t *editor,
-                           const char *relpath,
-                           svn_revnum_t revision,
-                           const apr_array_header_t *children,
-                           apr_hash_t *props)
+svn_editor3_put(svn_editor3_t *editor,
+                pathrev_t loc,
+                const svn_editor3_node_content_t *new_content)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT(children != NULL || props != NULL);
-  /* ### validate children are just basenames?  */
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ALTER(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_alter_directory)
+  if (editor->funcs.cb_put)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_alter_directory(editor->baton,
-                                             relpath, revision,
-                                             children, props,
-                                             editor->scratch_pool);
+      err = editor->funcs.cb_put(editor->baton,
+                                 loc, new_content,
+                                 editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
-
-#ifdef ENABLE_ORDERING_CHECK
-  /* ### this is not entirely correct. we probably need to adjust the
-     ### check_unknown_child() function for this scenario.  */
-#if 0
-  {
-    int i;
-    for (i = 0; i < children->nelts; i++)
-      {
-        const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
-        const char *child = svn_relpath_join(relpath, child_basename,
-                                             editor->state_pool);
-
-        apr_hash_set(editor->pending_incomplete_children, child,
-                     APR_HASH_KEY_STRING, "");
-        /* Perhaps MARK_ALLOW_ADD(editor, child); ? */
-      }
-  }
-#endif
-#endif
-
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
 
+/*
+ * ========================================================================
+ * Editor for Commit from WC, with Separate Unordered Per-Node Tree Changes
+ * ========================================================================
+ */
+
 svn_error_t *
-svn_editor_alter_file(svn_editor_t *editor,
-                      const char *relpath,
-                      svn_revnum_t revision,
-                      const svn_checksum_t *checksum,
-                      svn_stream_t *contents,
-                      apr_hash_t *props)
+svn_editor3_add(svn_editor3_t *editor,
+                svn_editor3_nbid_t local_nbid,
+                svn_node_kind_t new_kind,
+                svn_editor3_nbid_t new_parent_nbid,
+                const char *new_name,
+                const svn_editor3_node_content_t *new_content)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT((checksum != NULL && contents != NULL)
-                 || (checksum == NULL && contents == NULL));
-  SVN_ERR_ASSERT(props != NULL || checksum != NULL);
-  if (checksum)
-    SVN_ERR_ASSERT(checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ALTER(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_alter_file)
+  if (editor->funcs.cb_add)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_alter_file(editor->baton,
-                                        relpath, revision,
-                                        checksum, contents, props,
-                                        editor->scratch_pool);
+      err = editor->funcs.cb_add(editor->baton,
+                                 local_nbid, new_kind,
+                                 new_parent_nbid, new_name,
+                                 new_content,
+                                 editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
+  /* MARK_...(editor, ...); */
 
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_alter_symlink(svn_editor_t *editor,
-                         const char *relpath,
-                         svn_revnum_t revision,
-                         const char *target,
-                         apr_hash_t *props)
+svn_editor3_copy_one(svn_editor3_t *editor,
+                     svn_editor3_nbid_t local_nbid,
+                     svn_revnum_t src_revision,
+                     svn_editor3_nbid_t src_nbid,
+                     svn_editor3_nbid_t new_parent_nbid,
+                     const char *new_name,
+                     const svn_editor3_node_content_t *new_content)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SVN_ERR_ASSERT(props != NULL || target != NULL);
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ALTER(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_alter_symlink)
+  if (editor->funcs.cb_copy_one)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_alter_symlink(editor->baton,
-                                           relpath, revision,
-                                           target, props,
-                                           editor->scratch_pool);
+      err = editor->funcs.cb_copy_one(editor->baton,
+                                      local_nbid,
+                                      src_revision, src_nbid,
+                                      new_parent_nbid, new_name,
+                                      new_content,
+                                      editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
+  /* MARK_...(editor, ...); */
 
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_delete(svn_editor_t *editor,
-                  const char *relpath,
-                  svn_revnum_t revision)
+svn_editor3_copy_tree(svn_editor3_t *editor,
+                      svn_revnum_t src_revision,
+                      svn_editor3_nbid_t src_nbid,
+                      svn_editor3_nbid_t new_parent_nbid,
+                      const char *new_name)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_NOT_BE_COMPLETED(editor, relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, relpath);
-  CHILD_DELETIONS_ALLOWED(editor, relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_delete)
+  if (editor->funcs.cb_copy_one)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_delete(editor->baton, relpath, revision,
-                                    editor->scratch_pool);
+      err = editor->funcs.cb_copy_tree(editor->baton,
+                                       src_revision, src_nbid,
+                                       new_parent_nbid, new_name,
+                                       editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_COMPLETED(editor, relpath);
-  MARK_PARENT_STABLE(editor, relpath);
+  /* MARK_...(editor, ...); */
 
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_copy(svn_editor_t *editor,
-                const char *src_relpath,
-                svn_revnum_t src_revision,
-                const char *dst_relpath,
-                svn_revnum_t replaces_rev)
+svn_editor3_delete(svn_editor3_t *editor,
+                   svn_revnum_t since_rev,
+                   svn_editor3_nbid_t nbid)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_ALLOW_ADD(editor, dst_relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_copy)
+  if (editor->funcs.cb_delete)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
-                                  dst_relpath, replaces_rev,
-                                  editor->scratch_pool);
+      err = editor->funcs.cb_delete(editor->baton,
+                                    since_rev, nbid,
+                                    editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_ALLOW_ALTER(editor, dst_relpath);
-  MARK_PARENT_STABLE(editor, dst_relpath);
-  CLEAR_INCOMPLETE(editor, dst_relpath);
+  /* MARK_...(editor, ...); */
 
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_move(svn_editor_t *editor,
-                const char *src_relpath,
-                svn_revnum_t src_revision,
-                const char *dst_relpath,
-                svn_revnum_t replaces_rev)
+svn_editor3_alter(svn_editor3_t *editor,
+                  svn_revnum_t since_rev,
+                  svn_editor3_nbid_t nbid,
+                  svn_editor3_nbid_t new_parent_nbid,
+                  const char *new_name,
+                  const svn_editor3_node_content_t *new_content)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
-  SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
-  SHOULD_NOT_BE_FINISHED(editor);
-  SHOULD_NOT_BE_COMPLETED(editor, src_relpath);
-  SHOULD_ALLOW_ADD(editor, dst_relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
-  CHILD_DELETIONS_ALLOWED(editor, src_relpath);
-  VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
+  /* SVN_ERR_ASSERT(...); */
 
   SVN_ERR(check_cancel(editor));
 
-  if (editor->funcs.cb_move)
+  if (editor->funcs.cb_alter)
     {
       START_CALLBACK(editor);
-      err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
-                                  dst_relpath, replaces_rev,
-                                  editor->scratch_pool);
+      err = editor->funcs.cb_alter(editor->baton,
+                                   since_rev, nbid,
+                                   new_parent_nbid, new_name,
+                                   new_content,
+                                   editor->scratch_pool);
       END_CALLBACK(editor);
     }
 
-  MARK_ALLOW_ADD(editor, src_relpath);
-  MARK_PARENT_STABLE(editor, src_relpath);
-  MARK_ALLOW_ALTER(editor, dst_relpath);
-  MARK_PARENT_STABLE(editor, dst_relpath);
-  CLEAR_INCOMPLETE(editor, dst_relpath);
+  /* MARK_...(editor, ...); */
 
   svn_pool_clear(editor->scratch_pool);
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_complete(svn_editor_t *editor)
+svn_editor3_complete(svn_editor3_t *editor)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
   SHOULD_NOT_BE_FINISHED(editor);
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(apr_hash_count(editor->pending_incomplete_children) == 0);
-#endif
 
   if (editor->funcs.cb_complete)
     {
@@ -873,9 +464,8 @@ svn_editor_complete(svn_editor_t *editor
   return svn_error_trace(err);
 }
 
-
 svn_error_t *
-svn_editor_abort(svn_editor_t *editor)
+svn_editor3_abort(svn_editor3_t *editor)
 {
   svn_error_t *err = SVN_NO_ERROR;