You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/16 01:44:46 UTC

svn commit: r1532597 [4/10] - in /subversion/branches/log-addressing: ./ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ notes/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/a...

Modified: subversion/branches/log-addressing/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/include/svn_repos.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/include/svn_repos.h (original)
+++ subversion/branches/log-addressing/subversion/include/svn_repos.h Tue Oct 15 23:44:41 2013
@@ -1794,6 +1794,9 @@ svn_repos_node_location_segments(svn_rep
  * filesystem, as limited by @a paths. In the latter case those revisions
  * are skipped and @a receiver is not invoked.
  *
+ * @a move_behavior defines which changes are being reported as moves.
+ * See #svn_move_behavior_t for the various options.
+ *
  * If @a revprops is NULL, retrieve all revision properties; else, retrieve
  * only the revision properties named by the (const char *) array elements
  * (i.e. retrieve none if the array is empty).
@@ -1818,8 +1821,33 @@ svn_repos_node_location_segments(svn_rep
  *
  * Use @a pool for temporary allocations.
  *
+ * @since New in 1.9.
+ */
+svn_error_t *
+svn_repos_get_logs5(svn_repos_t *repos,
+                    const apr_array_header_t *paths,
+                    svn_revnum_t start,
+                    svn_revnum_t end,
+                    int limit,
+                    svn_boolean_t discover_changed_paths,
+                    svn_boolean_t strict_node_history,
+                    svn_boolean_t include_merged_revisions,
+                    svn_move_behavior_t move_behavior,
+                    const apr_array_header_t *revprops,
+                    svn_repos_authz_func_t authz_read_func,
+                    void *authz_read_baton,
+                    svn_log_entry_receiver_t receiver,
+                    void *receiver_baton,
+                    apr_pool_t *pool);
+
+/**
+ * Same as svn_repos_get_logs5(), but with @a move_behavior being set to
+ * #svn_fs_move_behavior_no_moves.
+ *
  * @since New in 1.5.
+ * @deprecated Provided for backward compatibility with the 1.8 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_repos_get_logs4(svn_repos_t *repos,
                     const apr_array_header_t *paths,

Modified: subversion/branches/log-addressing/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/include/svn_types.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/include/svn_types.h (original)
+++ subversion/branches/log-addressing/subversion/include/svn_types.h Tue Oct 15 23:44:41 2013
@@ -64,6 +64,26 @@ extern "C" {
 #endif
 
 
+/** Macro used to mark experimental functions.
+ *
+ * @since New in 1.9.
+ */
+#ifndef SVN_EXPERIMENTAL
+# if !defined(SWIGPERL) && !defined(SWIGPYTHON) && !defined(SWIGRUBY)
+#  if !defined(__clang__) && defined(__GNUC__) \
+      && (__GNUC__ >= 4 || (__GNUC__==3 && __GNUC_MINOR__>=1))
+#   define SVN_EXPERIMENTAL __attribute__((warning("experimental function used")))
+#  elif defined(_MSC_VER) && _MSC_VER >= 1300
+#   define SVN_EXPERIMENTAL __declspec(deprecated("experimental function used"))
+#  else
+#   define SVN_EXPERIMENTAL
+#  endif
+# else
+#  define SVN_EXPERIMENTAL
+# endif
+#endif
+
+
 /** Indicate whether the current platform supports unaligned data access.
  *
  * On the majority of machines running SVN (x86 / x64), unaligned access
@@ -219,6 +239,16 @@ svn__apr_hash_index_val(const apr_hash_i
                       || ((s) == APR_OS_START_SYSERR + ERROR_INVALID_NAME))
 #endif
 
+/** On Windows, APR_STATUS_IS_EPIPE does not include ERROR_NO_DATA error.
+ * So we include it.*/
+/* ### These fixes should go into APR. */
+#ifndef WIN32
+#define SVN__APR_STATUS_IS_EPIPE(s)  APR_STATUS_IS_EPIPE(s)
+#else
+#define SVN__APR_STATUS_IS_EPIPE(s)  (APR_STATUS_IS_EPIPE(s) \
+                      || ((s) == APR_OS_START_SYSERR + ERROR_NO_DATA))
+#endif
+
 /** @} */
 
 
@@ -752,7 +782,7 @@ svn_commit_info_dup(const svn_commit_inf
  */
 typedef struct svn_log_changed_path2_t
 {
-  /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify */
+  /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify, mo'V'ed, move-replac'E'd */
   char action;
 
   /** Source path of copy (if any). */
@@ -991,6 +1021,28 @@ typedef svn_error_t *(*svn_log_message_r
   const char *message,
   apr_pool_t *pool);
 
+/**
+ * This enumeration contains the various options how SVN shall report
+ * and process explicit MOVes as well as ADD+DEL pairs.
+ *
+ * @since New in 1.9.
+ */
+typedef enum svn_move_behavior_t
+{
+  /* report all moves as ADD with history.
+     This also provides backward compatibility with 1.8 clients. */
+  svn_move_behavior_no_moves = 0,
+
+  /* report all changes, including moves, as they were reported.
+     This is option with the least overhead. */
+  svn_move_behavior_explicit_moves,
+
+  /* in addition to explicit moves, try to find matching DEL + ADD pairs
+     and report the ADD in those as moves as well.  Which of the eligible
+     DEL + ADD pairs will be detected is implementation-dependent. */
+  svn_move_behavior_auto_moves
+} svn_move_behavior_t;
+
 
 
 /** Callback function type for commits.

Modified: subversion/branches/log-addressing/subversion/include/svn_version.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/include/svn_version.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/include/svn_version.h (original)
+++ subversion/branches/log-addressing/subversion/include/svn_version.h Tue Oct 15 23:44:41 2013
@@ -28,15 +28,13 @@
 #define SVN_VERSION_H
 
 /* Hack to prevent the resource compiler from including
-   apr_general.h.  It doesn't resolve the include paths
-   correctly and blows up without this.
- */
-#ifndef APR_STRINGIFY
+   apr and other headers. */
+#ifndef SVN_WIN32_RESOURCE_COMPILATION
 #include <apr_general.h>
-#endif
 #include <apr_tables.h>
 
 #include "svn_types.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {

Modified: subversion/branches/log-addressing/subversion/libsvn_client/add.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/add.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/add.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/add.c Tue Oct 15 23:44:41 2013
@@ -1243,35 +1243,34 @@ mkdir_urls(const apr_array_header_t *url
 
 
 svn_error_t *
-svn_client__make_local_parents(const char *path,
+svn_client__make_local_parents(const char *local_abspath,
                                svn_boolean_t make_parents,
                                svn_client_ctx_t *ctx,
-                               apr_pool_t *pool)
+                               apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   svn_node_kind_t orig_kind;
-  SVN_ERR(svn_io_check_path(path, &orig_kind, pool));
+  SVN_ERR(svn_io_check_path(local_abspath, &orig_kind, scratch_pool));
   if (make_parents)
-    SVN_ERR(svn_io_make_dir_recursively(path, pool));
+    SVN_ERR(svn_io_make_dir_recursively(local_abspath, scratch_pool));
   else
-    SVN_ERR(svn_io_dir_make(path, APR_OS_DEFAULT, pool));
+    SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, scratch_pool));
 
   /* Should no longer use svn_depth_empty to indicate that only the directory
      itself is added, since it not only constraints the operation depth, but
      also defines the depth of the target directory now. Moreover, the new
      directory will have no children at all.*/
-  err = svn_client_add5(path, svn_depth_infinity, FALSE, FALSE, FALSE,
-                        make_parents, ctx, pool);
+  err = svn_client_add5(local_abspath, svn_depth_infinity, FALSE, FALSE, FALSE,
+                        make_parents, ctx, scratch_pool);
 
   /* If we created a new directory, but couldn't add it to version
      control, then delete it. */
   if (err && (orig_kind == svn_node_none))
     {
-      /* ### If this returns an error, should we link it onto
-         err instead, so that the user is warned that we just
-         created an unversioned directory? */
-
-      svn_error_clear(svn_io_remove_dir2(path, FALSE, NULL, NULL, pool));
+      err = svn_error_compose_create(err,
+                                     svn_io_remove_dir2(local_abspath, FALSE,
+                                                        NULL, NULL,
+                                                        scratch_pool));
     }
 
   return svn_error_trace(err);
@@ -1300,23 +1299,25 @@ svn_client_mkdir4(const apr_array_header
   else
     {
       /* This is a regular "mkdir" + "svn add" */
-      apr_pool_t *subpool = svn_pool_create(pool);
+      apr_pool_t *iterpool = svn_pool_create(pool);
       int i;
 
       for (i = 0; i < paths->nelts; i++)
         {
           const char *path = APR_ARRAY_IDX(paths, i, const char *);
 
-          svn_pool_clear(subpool);
+          svn_pool_clear(iterpool);
 
           /* See if the user wants us to stop. */
           if (ctx->cancel_func)
             SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
+          SVN_ERR(svn_dirent_get_absolute(&path, path, iterpool));
+
           SVN_ERR(svn_client__make_local_parents(path, make_parents, ctx,
-                                                 subpool));
+                                                 iterpool));
         }
-      svn_pool_destroy(subpool);
+      svn_pool_destroy(iterpool);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/log-addressing/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/client.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/client.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/client.h Tue Oct 15 23:44:41 2013
@@ -466,10 +466,10 @@ svn_client__wc_delete_many(const apr_arr
                            apr_pool_t *pool);
 
 
-/* Make PATH and add it to the working copy, optionally making all the
-   intermediate parent directories if MAKE_PARENTS is TRUE. */
+/* Make LOCAL_ABSPATH and add it to the working copy, optionally making all
+   the intermediate parent directories if MAKE_PARENTS is TRUE. */
 svn_error_t *
-svn_client__make_local_parents(const char *path,
+svn_client__make_local_parents(const char *local_abspath,
                                svn_boolean_t make_parents,
                                svn_client_ctx_t *ctx,
                                apr_pool_t *pool);

Modified: subversion/branches/log-addressing/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/copy.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/copy.c Tue Oct 15 23:44:41 2013
@@ -1945,6 +1945,9 @@ try_copy(svn_boolean_t *timestamp_sleep,
   svn_boolean_t srcs_are_urls, dst_is_url;
   int i;
 
+  /* Assert instead of crashing if the sources list is empty. */
+  SVN_ERR_ASSERT(sources->nelts > 0);
+
   /* Are either of our paths URLs?  Just check the first src_path.  If
      there are more than one, we'll check for homogeneity among them
      down below. */

Modified: subversion/branches/log-addressing/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/deprecated.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/deprecated.c Tue Oct 15 23:44:41 2013
@@ -1498,6 +1498,28 @@ svn_client_ls(apr_hash_t **dirents,
 }
 
 /*** From log.c ***/
+
+svn_error_t *
+svn_client_log5(const apr_array_header_t *targets,
+                const svn_opt_revision_t *peg_revision,
+                const apr_array_header_t *revision_ranges,
+                int limit,
+                svn_boolean_t discover_changed_paths,
+                svn_boolean_t strict_node_history,
+                svn_boolean_t include_merged_revisions,
+                const apr_array_header_t *revprops,
+                svn_log_entry_receiver_t receiver,
+                void *receiver_baton,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *pool)
+{
+  return svn_client_log6(targets, peg_revision, revision_ranges, limit,
+                         discover_changed_paths, strict_node_history,
+                         include_merged_revisions,
+                         svn_move_behavior_no_moves, revprops, receiver,
+                         receiver_baton, ctx, pool);
+}
+
 svn_error_t *
 svn_client_log4(const apr_array_header_t *targets,
                 const svn_opt_revision_t *peg_revision,

Modified: subversion/branches/log-addressing/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/externals.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/externals.c Tue Oct 15 23:44:41 2013
@@ -738,7 +738,7 @@ handle_external_item_change(svn_client_c
   switch (ext_kind)
     {
       case svn_node_dir:
-        SVN_ERR(switch_dir_external(local_abspath, new_url,
+        SVN_ERR(switch_dir_external(local_abspath, new_loc->url,
                                     &(new_item->peg_revision),
                                     &(new_item->revision),
                                     parent_dir_abspath,

Modified: subversion/branches/log-addressing/subversion/libsvn_client/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/log.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/log.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/log.c Tue Oct 15 23:44:41 2013
@@ -610,6 +610,7 @@ run_ra_get_log(apr_array_header_t *revis
                svn_boolean_t discover_changed_paths,
                svn_boolean_t strict_node_history,
                svn_boolean_t include_merged_revisions,
+               svn_move_behavior_t move_behavior,
                const apr_array_header_t *revprops,
                svn_log_entry_receiver_t real_receiver,
                void *real_receiver_baton,
@@ -768,7 +769,7 @@ run_ra_get_log(apr_array_header_t *revis
           passed_receiver_baton = &lb;
         }
 
-      SVN_ERR(svn_ra_get_log2(ra_session,
+      SVN_ERR(svn_ra_get_log3(ra_session,
                               paths,
                               range->range_start,
                               range->range_end,
@@ -776,6 +777,7 @@ run_ra_get_log(apr_array_header_t *revis
                               discover_changed_paths,
                               strict_node_history,
                               include_merged_revisions,
+                              move_behavior,
                               passed_receiver_revprops,
                               passed_receiver,
                               passed_receiver_baton,
@@ -798,13 +800,14 @@ run_ra_get_log(apr_array_header_t *revis
 /*** Public Interface. ***/
 
 svn_error_t *
-svn_client_log5(const apr_array_header_t *targets,
+svn_client_log6(const apr_array_header_t *targets,
                 const svn_opt_revision_t *peg_revision,
                 const apr_array_header_t *opt_rev_ranges,
                 int limit,
                 svn_boolean_t discover_changed_paths,
                 svn_boolean_t strict_node_history,
                 svn_boolean_t include_merged_revisions,
+                svn_move_behavior_t move_behavior,
                 const apr_array_header_t *revprops,
                 svn_log_entry_receiver_t real_receiver,
                 void *real_receiver_baton,
@@ -890,8 +893,8 @@ svn_client_log5(const apr_array_header_t
   SVN_ERR(run_ra_get_log(revision_ranges, relative_targets, log_segments,
                          actual_loc, ra_session, targets, limit,
                          discover_changed_paths, strict_node_history,
-                         include_merged_revisions, revprops, real_receiver,
-                         real_receiver_baton, ctx, pool));
+                         include_merged_revisions, move_behavior, revprops,
+                         real_receiver, real_receiver_baton, ctx, pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/log-addressing/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/merge.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/merge.c Tue Oct 15 23:44:41 2013
@@ -10715,7 +10715,7 @@ log_find_operative_revs(void *baton,
 
           suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev,
                                              source_rel_path);
-          if (suffix)
+          if (suffix && suffix[0] != '\0')
             {
               missing_path = apr_pstrmemdup(pool, path,
                                             strlen(path) - strlen(suffix) - 1);
@@ -12301,7 +12301,16 @@ find_base_on_target(svn_client__pathrev_
   return SVN_NO_ERROR;
 }
 
-/* The body of client_find_automatic_merge(), which see.
+/* Find the last point at which the branch at S_T->source was completely
+ * merged to the branch at S_T->target or vice-versa.
+ *
+ * Fill in S_T->source_branch and S_T->target_branch and S_T->yca.
+ * Set *BASE_P to the merge base.  Set *IS_REINTEGRATE_LIKE to true if
+ * an automatic merge from source to target would be a reintegration
+ * merge: that is, if the last automatic merge was in the opposite
+ * direction; or to false otherwise.
+ *
+ * If there is no youngest common ancestor, throw an error.
  */
 static svn_error_t *
 find_automatic_merge(svn_client__pathrev_t **base_p,
@@ -12371,6 +12380,9 @@ find_automatic_merge(svn_client__pathrev
  * Like find_automatic_merge() except that the target is
  * specified by @a target_path_or_url at @a target_revision, which must
  * refer to a repository location, instead of by a WC path argument.
+ *
+ * Set *MERGE_P to a new structure with all fields filled in except the
+ * 'allow_*' flags.
  */
 static svn_error_t *
 find_automatic_merge_no_wc(automatic_merge_t **merge_p,
@@ -12446,6 +12458,8 @@ client_find_automatic_merge(automatic_me
   source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
   automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
 
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
+
   /* "Open" the target WC.  Check the target WC for mixed-rev, local mods and
    * switched subtrees yet to faster exit and notify user before contacting
    * with server.  After we find out what kind of merge is required, then if a
@@ -12477,6 +12491,7 @@ client_find_automatic_merge(automatic_me
                                ctx, result_pool, scratch_pool));
   merge->yca = s_t->yca;
   merge->right = s_t->source;
+  merge->target = &s_t->target->loc;
   merge->allow_mixed_rev = allow_mixed_rev;
   merge->allow_local_mods = allow_local_mods;
   merge->allow_switched_subtrees = allow_switched_subtrees;
@@ -12667,12 +12682,18 @@ svn_client_get_merging_summary(svn_boole
                  && (target_revision->kind == svn_opt_revision_unspecified
                      || target_revision->kind == svn_opt_revision_working);
   if (target_is_wc)
-    SVN_ERR(client_find_automatic_merge(
-              &merge,
-              source_path_or_url, source_revision,
-              target_path_or_url,
-              TRUE, TRUE, TRUE,  /* allow_* */
-              ctx, scratch_pool, scratch_pool));
+    {
+      const char *target_abspath;
+
+      SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_path_or_url,
+                                      scratch_pool));
+      SVN_ERR(client_find_automatic_merge(
+                &merge,
+                source_path_or_url, source_revision,
+                target_abspath,
+                TRUE, TRUE, TRUE,  /* allow_* */
+                ctx, scratch_pool, scratch_pool));
+    }
   else
     SVN_ERR(find_automatic_merge_no_wc(
               &merge,

Modified: subversion/branches/log-addressing/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/mergeinfo.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/mergeinfo.c Tue Oct 15 23:44:41 2013
@@ -1405,17 +1405,21 @@ filter_log_entry_with_rangelist(void *ba
              obviously back.  If it was added or replaced it's still around
              possibly it was replaced one or more times, but it's back now.
              Regardless, LOG_ENTRY->REVISION is *not* an eligible revision! */
-          if (ancestor_is_self /* Explicit mergeinfo on TARGET_PATH_AFFECTED */
+          if (nearest_ancestor_mergeinfo &&
+              ancestor_is_self /* Explicit mergeinfo on TARGET_PATH_AFFECTED */
               && (change->action != 'M'))
             {
               svn_rangelist_t *rangelist =
                   svn_hash_gets(nearest_ancestor_mergeinfo, path);
-              svn_merge_range_t *youngest_range = APR_ARRAY_IDX(
-                rangelist, rangelist->nelts - 1, svn_merge_range_t *);
+              if (rangelist)
+                {
+                  svn_merge_range_t *youngest_range = APR_ARRAY_IDX(
+                    rangelist, rangelist->nelts - 1, svn_merge_range_t *);
 
-              if (youngest_range
-                  && (youngest_range->end > log_entry->revision))
-                continue;
+                  if (youngest_range
+                      && (youngest_range->end > log_entry->revision))
+                    continue;
+                }
             }
 
           if (nearest_ancestor_mergeinfo)

Modified: subversion/branches/log-addressing/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_client/ra.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_client/ra.c Tue Oct 15 23:44:41 2013
@@ -350,6 +350,10 @@ svn_client__open_ra_session_internal(svn
   cbtable->get_client_string = get_client_string;
   if (base_dir_abspath)
     cbtable->get_wc_contents = get_wc_contents;
+  cbtable->check_tunnel_func = ctx->check_tunnel_func;
+  cbtable->open_tunnel_func = ctx->open_tunnel_func;
+  cbtable->close_tunnel_func = ctx->close_tunnel_func;
+  cbtable->tunnel_baton = ctx->tunnel_baton;
 
   cb->commit_items = commit_items;
   cb->ctx = ctx;

Modified: subversion/branches/log-addressing/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_delta/compat.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_delta/compat.c Tue Oct 15 23:44:41 2013
@@ -1330,17 +1330,6 @@ move_cb(void *baton,
   return SVN_NO_ERROR;
 }
 
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
-          const apr_array_header_t *relpaths,
-          const apr_array_header_t *revisions,
-          apr_pool_t *scratch_pool)
-{
-  SVN__NOT_IMPLEMENTED();
-}
-
-
 static int
 count_components(const char *relpath)
 {
@@ -1888,7 +1877,6 @@ svn_delta__editor_from_delta(svn_editor_
       delete_cb,
       copy_cb,
       move_cb,
-      rotate_cb,
       complete_cb,
       abort_cb
     };

Modified: subversion/branches/log-addressing/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_delta/editor.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_delta/editor.c Tue Oct 15 23:44:41 2013
@@ -391,16 +391,6 @@ svn_editor_setcb_move(svn_editor_t *edit
 
 
 svn_error_t *
-svn_editor_setcb_rotate(svn_editor_t *editor,
-                        svn_editor_cb_rotate_t callback,
-                        apr_pool_t *scratch_pool)
-{
-  editor->funcs.cb_rotate = callback;
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
 svn_editor_setcb_complete(svn_editor_t *editor,
                           svn_editor_cb_complete_t callback,
                           apr_pool_t *scratch_pool)
@@ -437,7 +427,6 @@ svn_editor_setcb_many(svn_editor_t *edit
   COPY_CALLBACK(cb_delete);
   COPY_CALLBACK(cb_copy);
   COPY_CALLBACK(cb_move);
-  COPY_CALLBACK(cb_rotate);
   COPY_CALLBACK(cb_complete);
   COPY_CALLBACK(cb_abort);
 
@@ -862,56 +851,6 @@ svn_editor_move(svn_editor_t *editor,
 
 
 svn_error_t *
-svn_editor_rotate(svn_editor_t *editor,
-                  const apr_array_header_t *relpaths,
-                  const apr_array_header_t *revisions)
-{
-  svn_error_t *err = SVN_NO_ERROR;
-
-  SHOULD_NOT_BE_FINISHED(editor);
-#ifdef ENABLE_ORDERING_CHECK
-  {
-    int i;
-    for (i = 0; i < relpaths->nelts; i++)
-      {
-        const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
-
-        SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
-        SHOULD_NOT_BE_COMPLETED(editor, relpath);
-        VERIFY_PARENT_MAY_EXIST(editor, relpath);
-        CHILD_DELETIONS_ALLOWED(editor, relpath);
-      }
-  }
-#endif
-
-  SVN_ERR(check_cancel(editor));
-
-  if (editor->funcs.cb_rotate)
-    {
-      START_CALLBACK(editor);
-      err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
-                                    editor->scratch_pool);
-      END_CALLBACK(editor);
-    }
-
-#ifdef ENABLE_ORDERING_CHECK
-  {
-    int i;
-    for (i = 0; i < relpaths->nelts; i++)
-      {
-        const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
-        MARK_ALLOW_ALTER(editor, relpath);
-        MARK_PARENT_STABLE(editor, relpath);
-      }
-  }
-#endif
-
-  svn_pool_clear(editor->scratch_pool);
-  return svn_error_trace(err);
-}
-
-
-svn_error_t *
 svn_editor_complete(svn_editor_t *editor)
 {
   svn_error_t *err = SVN_NO_ERROR;

Modified: subversion/branches/log-addressing/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs/editor.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs/editor.c Tue Oct 15 23:44:41 2013
@@ -177,7 +177,7 @@ can_modify(svn_fs_root_t *txn_root,
   SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
                                   scratch_pool));
 
-  /* Uncommitted nodes (eg. a descendent of a copy/move/rotate destination)
+  /* Uncommitted nodes (eg. a descendent of a copy/move destination)
      have no (committed) revision number. Let the caller go ahead and
      modify these nodes.
 
@@ -195,7 +195,7 @@ can_modify(svn_fs_root_t *txn_root,
      have supplied a valid revision number [that they expect to change].
      The checks further below will determine the out-of-dateness of the
      specified revision.  */
-  /* ### ugh. descendents of copy/move/rotate destinations carry along
+  /* ### ugh. descendents of copy/move destinations carry along
      ### their original immutable state and (thus) a valid CREATED_REV.
      ### but they are logically uncommitted, so the caller will pass
      ### SVN_INVALID_REVNUM. (technically, the caller could provide
@@ -205,7 +205,7 @@ can_modify(svn_fs_root_t *txn_root,
      ### for now, we will assume the caller knows what they are doing
      ### and an invalid revision implies such a descendent. in the
      ### future, we could examine the ancestor chain looking for a
-     ### copy/move/rotate-here node and allow the modification (and the
+     ### copy/move-here node and allow the modification (and the
      ### converse: if no such ancestor, the caller must specify the
      ### correct/intended revision to modify).
   */
@@ -299,7 +299,7 @@ can_create(svn_fs_root_t *txn_root,
      ### test the ancestor to determine if it has been *-here in this
      ### txn, or just a simple modification.  */
 
-  /* Are any of the parents copied/moved/rotated-here?  */
+  /* Are any of the parents copied/moved-here?  */
   for (cur_fspath = fspath;
        strlen(cur_fspath) > 1;  /* not the root  */
        cur_fspath = svn_fspath__dirname(cur_fspath, scratch_pool))
@@ -633,19 +633,6 @@ move_cb(void *baton,
 }
 
 
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
-          const apr_array_header_t *relpaths,
-          const apr_array_header_t *revisions,
-          apr_pool_t *scratch_pool)
-{
-  struct edit_baton *eb = baton;
-
-  UNUSED(eb); SVN__NOT_IMPLEMENTED();
-}
-
-
 /* This implements svn_editor_cb_complete_t */
 static svn_error_t *
 complete_cb(void *baton,
@@ -714,7 +701,6 @@ make_editor(svn_editor_t **editor,
     delete_cb,
     copy_cb,
     move_cb,
-    rotate_cb,
     complete_cb,
     abort_cb
   };

Modified: subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.c Tue Oct 15 23:44:41 2013
@@ -24,6 +24,7 @@
 
 #include <string.h>
 #include <apr.h>
+#include <apr_atomic.h>
 #include <apr_hash.h>
 #include <apr_md5.h>
 #include <apr_thread_mutex.h>
@@ -41,6 +42,7 @@
 #include "svn_xml.h"
 #include "svn_pools.h"
 #include "svn_string.h"
+#include "svn_sorts.h"
 
 #include "private/svn_fs_private.h"
 #include "private/svn_fs_util.h"
@@ -70,6 +72,7 @@ struct fs_type_defn {
   const char *fs_type;
   const char *fsap_name;
   fs_init_func_t initfunc;
+  fs_library_vtable_t *vtable;
   struct fs_type_defn *next;
 };
 
@@ -81,7 +84,9 @@ static struct fs_type_defn base_defn =
 #else
     NULL,
 #endif
-    NULL
+    NULL,
+    NULL /* End of static list: this needs to be reset to NULL if the
+            common_pool used when setting it has been cleared. */
   };
 
 static struct fs_type_defn fsx_defn =
@@ -92,6 +97,7 @@ static struct fs_type_defn fsx_defn =
 #else
     NULL,
 #endif
+    NULL,
     &base_defn
   };
 
@@ -103,6 +109,7 @@ static struct fs_type_defn fsfs_defn =
 #else
     NULL,
 #endif
+    NULL,
     &fsx_defn
   };
 
@@ -158,13 +165,20 @@ load_module(fs_init_func_t *initfunc, co
 /* Fetch a library vtable by a pointer into the library definitions array. */
 static svn_error_t *
 get_library_vtable_direct(fs_library_vtable_t **vtable,
-                          const struct fs_type_defn *fst,
+                          struct fs_type_defn *fst,
                           apr_pool_t *pool)
 {
   fs_init_func_t initfunc = NULL;
   const svn_version_t *my_version = svn_fs_version();
   const svn_version_t *fs_version;
 
+  /* most times, we get lucky */
+  *vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL);
+  if (*vtable)
+    return SVN_NO_ERROR;
+
+  /* o.k. the first access needs to actually load the module, find the
+     vtable and check for version compatibility. */
   initfunc = fst->initfunc;
   if (! initfunc)
     SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
@@ -201,6 +215,10 @@ get_library_vtable_direct(fs_library_vta
                              my_version->patch, my_version->tag,
                              fs_version->major, fs_version->minor,
                              fs_version->patch, fs_version->tag);
+
+  /* the vtable will not change.  Remember it */
+  apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL);
+
   return SVN_NO_ERROR;
 }
 
@@ -364,6 +382,7 @@ svn_fs_initialize(apr_pool_t *pool)
     return SVN_NO_ERROR;
 
   common_pool = svn_pool_create(pool);
+  base_defn.next = NULL;
   SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
 
   /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO
@@ -467,8 +486,7 @@ svn_fs_create(svn_fs_t **fs_p, const cha
   /* Perform the actual creation. */
   *fs_p = fs_new(fs_config, pool);
 
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->create(*fs_p, path, pool, common_pool));
+  SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool));
   SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
 
   return SVN_NO_ERROR;
@@ -482,8 +500,7 @@ svn_fs_open(svn_fs_t **fs_p, const char 
 
   SVN_ERR(fs_library_vtable(&vtable, path, pool));
   *fs_p = fs_new(fs_config, pool);
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->open_fs(*fs_p, path, pool, common_pool));
+  SVN_ERR(vtable->open_fs(*fs_p, path, common_pool_lock, pool, common_pool));
   SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
 
   return SVN_NO_ERROR;
@@ -503,11 +520,11 @@ svn_fs_upgrade2(const char *path,
   SVN_ERR(fs_library_vtable(&vtable, path, pool));
   fs = fs_new(NULL, pool);
 
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->upgrade_fs(fs, path,
-                                          notify_func, notify_baton,
-                                          cancel_func, cancel_baton,
-                                          pool, common_pool));
+  SVN_ERR(vtable->upgrade_fs(fs, path,
+                             notify_func, notify_baton,
+                             cancel_func, cancel_baton,
+                             common_pool_lock,
+                             pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -534,11 +551,11 @@ svn_fs_verify(const char *path,
   SVN_ERR(fs_library_vtable(&vtable, path, pool));
   fs = fs_new(fs_config, pool);
 
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->verify_fs(fs, path, start, end,
-                                         notify_func, notify_baton,
-                                         cancel_func, cancel_baton,
-                                         pool, common_pool));
+  SVN_ERR(vtable->verify_fs(fs, path, start, end,
+                            notify_func, notify_baton,
+                            cancel_func, cancel_baton,
+                            common_pool_lock,
+                            pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -649,10 +666,9 @@ svn_fs_pack(const char *path,
   SVN_ERR(fs_library_vtable(&vtable, path, pool));
   fs = fs_new(NULL, pool);
 
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->pack_fs(fs, path, notify_func, notify_baton,
-                                       cancel_func, cancel_baton, pool,
-                                       common_pool));
+  SVN_ERR(vtable->pack_fs(fs, path, notify_func, notify_baton,
+                          cancel_func, cancel_baton, common_pool_lock,
+                          pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -667,9 +683,8 @@ svn_fs_recover(const char *path,
   SVN_ERR(fs_library_vtable(&vtable, path, pool));
   fs = fs_new(NULL, pool);
 
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->open_fs_for_recovery(fs, path, pool,
-                                                    common_pool));
+  SVN_ERR(vtable->open_fs_for_recovery(fs, path, common_pool_lock,
+                                       pool, common_pool));
   return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton,
                                          pool));
 }
@@ -710,8 +725,7 @@ svn_fs_create_berkeley(svn_fs_t *fs, con
   SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
 
   /* Perform the actual creation. */
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->create(fs, path, fs->pool, common_pool));
+  SVN_ERR(vtable->create(fs, path, common_pool_lock, fs->pool, common_pool));
   SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
 
   return SVN_NO_ERROR;
@@ -723,8 +737,7 @@ svn_fs_open_berkeley(svn_fs_t *fs, const
   fs_library_vtable_t *vtable;
 
   SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
-  SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->open_fs(fs, path, fs->pool, common_pool));
+  SVN_ERR(vtable->open_fs(fs, path, common_pool_lock, fs->pool, common_pool));
   SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
 
   return SVN_NO_ERROR;
@@ -976,11 +989,177 @@ svn_fs_revision_root_revision(svn_fs_roo
   return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
 }
 
+/* Return TRUE, if CHANGE deleted the node previously found at its target
+   path. */
+static svn_boolean_t
+is_deletion(svn_fs_path_change2_t *change)
+{
+  return change->change_kind == svn_fs_path_change_movereplace
+      || change->change_kind == svn_fs_path_change_replace
+      || change->change_kind == svn_fs_path_change_delete;
+}
+
+/* Change all moves in CHANGES to ADD.  Use POOL for temporary allocations.
+ */
+static void
+turn_moves_into_copies(apr_hash_t *changes,
+                       apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      const char *key;
+      apr_ssize_t klen;
+      svn_fs_path_change2_t *change;
+      apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+
+      switch (change->change_kind)
+        {
+          case svn_fs_path_change_move:
+            change->change_kind = svn_fs_path_change_add;
+            break;
+
+          case svn_fs_path_change_movereplace:
+            change->change_kind = svn_fs_path_change_replace;
+            break;
+
+          default:
+            break;
+        }
+    }
+}
+
+/* Replace ADDs with MOVes, if they are unique, have a matching deletion
+ * and if the copy-from revision is REVISION-1.  Use POOL for temporary
+ * allocations.
+ */
+static void
+turn_unique_copies_into_moves(apr_hash_t *changes,
+                              svn_revnum_t revision,
+                              apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  apr_hash_t *unique_copy_sources;
+  const char **sources;
+  int i;
+
+  /* find all copy-from paths (ADD and MOV alike) */
+
+  svn_boolean_t any_deletion = FALSE;
+  apr_array_header_t *copy_sources
+    = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
+
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      svn_fs_path_change2_t *change;
+      apr_hash_this(hi, NULL, NULL, (void**)&change);
+
+      if (change->copyfrom_path && change->copyfrom_rev == revision-1)
+        APR_ARRAY_PUSH(copy_sources, const char *)
+          = change->copyfrom_path;
+
+      any_deletion |= is_deletion(change);
+    }
+
+  /* no suitable copy-from or no deletion -> no moves */
+
+  if (!copy_sources->nelts || !any_deletion)
+    return;
+
+  /* identify copy-from paths that have been mentioned exactly once */
+
+  sources = (const char **)copy_sources->elts;
+  qsort(sources, copy_sources->nelts, copy_sources->elt_size,
+        (int (*)(const void *, const void *))svn_sort_compare_paths);
+
+  unique_copy_sources = apr_hash_make(pool);
+  for (i = 0; i < copy_sources->nelts; ++i)
+    if (   (i == 0 || strcmp(sources[i-1], sources[i]))
+        && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
+      {
+        apr_hash_set(unique_copy_sources, sources[i],
+                     APR_HASH_KEY_STRING, sources[i]);
+      }
+
+  /* no unique copy-from paths -> no moves */
+
+  if (!apr_hash_count(unique_copy_sources))
+    return;
+
+  /* Replace all additions, replacements with a unique copy-from path,
+     the correct copy-from rev and a matching deletion in this revision,
+     with moves and move-replacements, respectively. */
+
+  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+    {
+      const char *key;
+      apr_ssize_t klen;
+      svn_fs_path_change2_t *change, *copy_from_change;
+
+      apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+      if (   change->copyfrom_rev != revision-1
+          || !change->copyfrom_path
+          || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
+                           APR_HASH_KEY_STRING))
+        continue;
+
+      copy_from_change = apr_hash_get(changes, change->copyfrom_path,
+                                      APR_HASH_KEY_STRING);
+      if (!copy_from_change || !is_deletion(copy_from_change))
+        continue;
+
+      /* There is a deletion of the ADD's copy-from path in *REVISION*.
+         This can either be the same as in REVISION-1 (o.k.) or must have
+         been replaced by some other node.  However, that would imply that
+         it still got deleted as part of the replacement, i.e. both cases
+         are o.k. */
+
+      switch (change->change_kind)
+        {
+          case svn_fs_path_change_add:
+            change->change_kind = svn_fs_path_change_move;
+            break;
+
+          case svn_fs_path_change_replace:
+            change->change_kind = svn_fs_path_change_movereplace;
+            break;
+
+          default:
+            break;
+        }
+    }
+}
+
+svn_error_t *
+svn_fs_paths_changed3(apr_hash_t **changed_paths_p,
+                      svn_fs_root_t *root,
+                      svn_move_behavior_t move_behavior,
+                      apr_pool_t *pool)
+{
+  SVN_ERR(root->vtable->paths_changed(changed_paths_p, root, pool));
+  switch(move_behavior)
+    {
+      case svn_move_behavior_no_moves:
+        turn_moves_into_copies(*changed_paths_p, pool);
+        break;
+
+      case svn_move_behavior_auto_moves:
+        turn_unique_copies_into_moves(*changed_paths_p, root->rev, pool);
+        break;
+
+      default:
+        break;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
                       apr_pool_t *pool)
 {
-  return root->vtable->paths_changed(changed_paths_p, root, pool);
+  return svn_fs_paths_changed3(changed_paths_p, root,
+                               svn_move_behavior_no_moves, pool);
 }
 
 svn_error_t *
@@ -990,7 +1169,8 @@ svn_fs_paths_changed(apr_hash_t **change
   apr_hash_t *changed_paths_new_structs;
   apr_hash_index_t *hi;
 
-  SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
+  SVN_ERR(svn_fs_paths_changed3(&changed_paths_new_structs, root,
+                                svn_move_behavior_no_moves, pool));
   *changed_paths_p = apr_hash_make(pool);
   for (hi = apr_hash_first(pool, changed_paths_new_structs);
        hi;
@@ -1224,6 +1404,15 @@ svn_fs_revision_link(svn_fs_root_t *from
 }
 
 svn_error_t *
+svn_fs_move(svn_fs_root_t *from_root, const char *from_path,
+            svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
+{
+  SVN_ERR(svn_fs__path_valid(to_path, pool));
+  return svn_error_trace(to_root->vtable->move(from_root, from_path,
+                                               to_root, to_path, pool));
+}
+
+svn_error_t *
 svn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
                    const char *path, apr_pool_t *pool)
 {
@@ -1623,7 +1812,7 @@ svn_error_t *
 svn_fs_print_modules(svn_stringbuf_t *output,
                      apr_pool_t *pool)
 {
-  const struct fs_type_defn *defn = fs_modules;
+  struct fs_type_defn *defn = fs_modules;
   fs_library_vtable_t *vtable;
   apr_pool_t *iterpool = svn_pool_create(pool);
 

Modified: subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs/fs-loader.h Tue Oct 15 23:44:41 2013
@@ -27,6 +27,7 @@
 
 #include "svn_types.h"
 #include "svn_fs.h"
+#include "private/svn_mutex.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -72,17 +73,22 @@ typedef struct fs_library_vtable_t
      this statement, now that the minor version has increased. */
   const svn_version_t *(*get_version)(void);
 
-  /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions are
-     serialized so that they may use the common_pool parameter to
-     allocate fs-global objects such as the bdb env cache. */
-  svn_error_t *(*create)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+  /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions must
+     use the common_pool_lock to serialize the access to the common_pool
+     parameter for allocating fs-global objects such as an env cache. */
+  svn_error_t *(*create)(svn_fs_t *fs, const char *path,
+                         svn_mutex__t *common_pool_lock,
+                         apr_pool_t *pool,
                          apr_pool_t *common_pool);
-  svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+  svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path,
+                          svn_mutex__t *common_pool_lock,
+                          apr_pool_t *pool,
                           apr_pool_t *common_pool);
   /* open_for_recovery() is like open(), but used to fill in an fs pointer
      that will be passed to recover().  We assume that the open() method
      might not be immediately appropriate for recovery. */
   svn_error_t *(*open_fs_for_recovery)(svn_fs_t *fs, const char *path,
+                                       svn_mutex__t *common_pool_lock,
                                        apr_pool_t *pool,
                                        apr_pool_t *common_pool);
   svn_error_t *(*upgrade_fs)(svn_fs_t *fs,
@@ -91,6 +97,7 @@ typedef struct fs_library_vtable_t
                              void *notify_baton,
                              svn_cancel_func_t cancel_func,
                              void *cancel_baton,
+                             svn_mutex__t *common_pool_lock,
                              apr_pool_t *pool,
                              apr_pool_t *common_pool);
   svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
@@ -100,6 +107,7 @@ typedef struct fs_library_vtable_t
                             void *notify_baton,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
+                            svn_mutex__t *common_pool_lock,
                             apr_pool_t *pool,
                             apr_pool_t *common_pool);
   svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
@@ -115,6 +123,7 @@ typedef struct fs_library_vtable_t
   svn_error_t *(*pack_fs)(svn_fs_t *fs, const char *path,
                           svn_fs_pack_notify_t notify_func, void *notify_baton,
                           svn_cancel_func_t cancel_func, void *cancel_baton,
+                          svn_mutex__t *common_pool_lock,
                           apr_pool_t *pool, apr_pool_t *common_pool);
 
   /* Provider-specific functions should go here, even if they could go
@@ -301,6 +310,16 @@ typedef struct root_vtable_t
                                     apr_pool_t *pool);
   svn_error_t *(*delete_node)(svn_fs_root_t *root, const char *path,
                               apr_pool_t *pool);
+  svn_error_t *(*copy)(svn_fs_root_t *from_root, const char *from_path,
+                       svn_fs_root_t *to_root, const char *to_path,
+                       apr_pool_t *pool);
+  svn_error_t *(*revision_link)(svn_fs_root_t *from_root,
+                                svn_fs_root_t *to_root,
+                                const char *path,
+                                apr_pool_t *pool);
+  svn_error_t *(*move)(svn_fs_root_t *from_root, const char *from_path,
+                       svn_fs_root_t *to_root, const char *to_path,
+                       apr_pool_t *pool);
   svn_error_t *(*copied_from)(svn_revnum_t *rev_p, const char **path_p,
                               svn_fs_root_t *root, const char *path,
                               apr_pool_t *pool);
@@ -331,13 +350,6 @@ typedef struct root_vtable_t
                                     apr_pool_t *pool);
   svn_error_t *(*make_dir)(svn_fs_root_t *root, const char *path,
                            apr_pool_t *pool);
-  svn_error_t *(*copy)(svn_fs_root_t *from_root, const char *from_path,
-                       svn_fs_root_t *to_root, const char *to_path,
-                       apr_pool_t *pool);
-  svn_error_t *(*revision_link)(svn_fs_root_t *from_root,
-                                svn_fs_root_t *to_root,
-                                const char *path,
-                                apr_pool_t *pool);
 
   /* Files */
   svn_error_t *(*file_length)(svn_filesize_t *length_p, svn_fs_root_t *root,

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_base/fs.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_base/fs.c Tue Oct 15 23:44:41 2013
@@ -729,7 +729,10 @@ populate_opened_fs(svn_fs_t *fs, apr_poo
 }
 
 static svn_error_t *
-base_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_create(svn_fs_t *fs,
+            const char *path,
+            svn_mutex__t *common_pool_lock,
+            apr_pool_t *pool,
             apr_pool_t *common_pool)
 {
   int format = SVN_FS_BASE__FORMAT_NUMBER;
@@ -820,7 +823,10 @@ check_format(int format)
 }
 
 static svn_error_t *
-base_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_open(svn_fs_t *fs,
+          const char *path,
+          svn_mutex__t *common_pool_lock,
+          apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
   int format;
@@ -903,7 +909,10 @@ bdb_recover(const char *path, svn_boolea
 }
 
 static svn_error_t *
-base_open_for_recovery(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_open_for_recovery(svn_fs_t *fs,
+                       const char *path,
+                       svn_mutex__t *common_pool_lock,
+                       apr_pool_t *pool,
                        apr_pool_t *common_pool)
 {
   /* Just stash the path in the fs pointer - it's all we really need. */
@@ -919,6 +928,7 @@ base_upgrade(svn_fs_t *fs,
              void *notify_baton,
              svn_cancel_func_t cancel_func,
              void *cancel_baton,
+             svn_mutex__t *common_pool_lock,
              apr_pool_t *pool,
              apr_pool_t *common_pool)
 {
@@ -961,7 +971,7 @@ base_upgrade(svn_fs_t *fs,
          But it's better to use the existing encapsulation of "opening
          the filesystem" rather than duplicating (or worse, partially
          duplicating) that logic here.  */
-      SVN_ERR(base_open(fs, path, subpool, common_pool));
+      SVN_ERR(base_open(fs, path, common_pool_lock, subpool, common_pool));
 
       /* Fetch the youngest rev, and record it */
       SVN_ERR(svn_fs_base__youngest_rev(&youngest_rev, fs, subpool));
@@ -983,6 +993,7 @@ base_verify(svn_fs_t *fs, const char *pa
             void *notify_baton,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
+            svn_mutex__t *common_pool_lock,
             apr_pool_t *pool,
             apr_pool_t *common_pool)
 {
@@ -1007,6 +1018,7 @@ base_bdb_pack(svn_fs_t *fs,
               void *notify_baton,
               svn_cancel_func_t cancel,
               void *cancel_baton,
+              svn_mutex__t *common_pool_lock,
               apr_pool_t *pool,
               apr_pool_t *common_pool)
 {

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_base/tree.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_base/tree.c Tue Oct 15 23:44:41 2013
@@ -3277,6 +3277,18 @@ base_revision_link(svn_fs_root_t *from_r
 }
 
 
+static svn_error_t *
+base_move(svn_fs_root_t *from_root,
+          const char *from_path,
+          svn_fs_root_t *to_root,
+          const char *to_path,
+          apr_pool_t *pool)
+{
+  /* BDB supports MOVes only as backward compatible ADD-with-history */
+  return base_copy(from_root, from_path, to_root, to_path, pool);
+}
+
+
 struct copied_from_args
 {
   svn_fs_root_t *root;      /* Root for the node whose ancestry we seek. */
@@ -5395,6 +5407,9 @@ static root_vtable_t root_vtable = {
   base_node_origin_rev,
   base_node_created_path,
   base_delete_node,
+  base_copy,
+  base_revision_link,
+  base_move,
   base_copied_from,
   base_closest_copy,
   base_node_prop,
@@ -5404,8 +5419,6 @@ static root_vtable_t root_vtable = {
   base_dir_entries,
   base_dir_optimal_order,
   base_make_dir,
-  base_copy,
-  base_revision_link,
   base_file_length,
   base_file_checksum,
   base_file_contents,

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.c Tue Oct 15 23:44:41 2013
@@ -313,7 +313,7 @@ get_node_revision_body(node_revision_t *
 
       /* noderevs in rev / pack files can be cached */
       const svn_fs_fs__id_part_t *rev_item = svn_fs_fs__id_rev_item(id);
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
       key.revision = rev_item->revision;
       key.second = rev_item->number;
 
@@ -1899,12 +1899,12 @@ get_dir_contents(apr_hash_t *entries,
       apr_size_t len = noderev->data_rep->expanded_size
                      ? (apr_size_t)noderev->data_rep->expanded_size
                      : (apr_size_t)noderev->data_rep->size;
-      svn_stringbuf_t *text = svn_stringbuf_create_ensure(len, text_pool);
-      text->len = len;
+      svn_stringbuf_t *text;
 
       /* The representation is immutable.  Read it normally. */
-      SVN_ERR(svn_fs_fs__get_contents(&contents, fs, noderev->data_rep, text_pool));
-      SVN_ERR(svn_stream_read(contents, text->data, &text->len));
+      SVN_ERR(svn_fs_fs__get_contents(&contents, fs, noderev->data_rep,
+                                      text_pool));
+      SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, text_pool));
       SVN_ERR(svn_stream_close(contents));
 
       /* de-serialize hash */

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.h Tue Oct 15 23:44:41 2013
@@ -138,4 +138,4 @@ svn_fs_fs__get_changes(apr_array_header_
                        svn_revnum_t rev,
                        apr_pool_t *pool);
 
-#endif
\ No newline at end of file
+#endif

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/cached_data.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.c Tue Oct 15 23:44:41 2013
@@ -231,9 +231,12 @@ initialize_fs_struct(svn_fs_t *fs)
 /* This implements the fs_library_vtable_t.create() API.  Create a new
    fsfs-backed Subversion filesystem at path PATH and link it into
    *FS.  Perform temporary allocations in POOL, and fs-global allocations
-   in COMMON_POOL. */
+   in COMMON_POOL.  The latter must be serialized using COMMON_POOL_LOCK. */
 static svn_error_t *
-fs_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+fs_create(svn_fs_t *fs,
+          const char *path,
+          svn_mutex__t *common_pool_lock,
+          apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
   SVN_ERR(svn_fs__check_fs(fs, FALSE));
@@ -243,7 +246,10 @@ fs_create(svn_fs_t *fs, const char *path
   SVN_ERR(svn_fs_fs__create(fs, path, pool));
 
   SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
-  return fs_serialized_init(fs, common_pool, pool);
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       fs_serialized_init(fs, common_pool, pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -253,17 +259,26 @@ fs_create(svn_fs_t *fs, const char *path
 /* This implements the fs_library_vtable_t.open() API.  Open an FSFS
    Subversion filesystem located at PATH, set *FS to point to the
    correct vtable for the filesystem.  Use POOL for any temporary
-   allocations, and COMMON_POOL for fs-global allocations. */
+   allocations, and COMMON_POOL for fs-global allocations.
+   The latter must be serialized using COMMON_POOL_LOCK. */
 static svn_error_t *
-fs_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+fs_open(svn_fs_t *fs,
+        const char *path,
+        svn_mutex__t *common_pool_lock,
+        apr_pool_t *pool,
         apr_pool_t *common_pool)
 {
+  SVN_ERR(svn_fs__check_fs(fs, FALSE));
+
   SVN_ERR(initialize_fs_struct(fs));
 
   SVN_ERR(svn_fs_fs__open(fs, path, pool));
 
   SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
-  return fs_serialized_init(fs, common_pool, pool);
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       fs_serialized_init(fs, common_pool, pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -272,7 +287,9 @@ fs_open(svn_fs_t *fs, const char *path, 
 static svn_error_t *
 fs_open_for_recovery(svn_fs_t *fs,
                      const char *path,
-                     apr_pool_t *pool, apr_pool_t *common_pool)
+                     svn_mutex__t *common_pool_lock,
+                     apr_pool_t *pool,
+                     apr_pool_t *common_pool)
 {
   /* Recovery for FSFS is currently limited to recreating the 'current'
      file from the latest revision. */
@@ -290,7 +307,7 @@ fs_open_for_recovery(svn_fs_t *fs,
                                      "0 1 1\n", pool));
 
   /* Now open the filesystem properly by calling the vtable method directly. */
-  return fs_open(fs, path, pool, common_pool);
+  return fs_open(fs, path, common_pool_lock, pool, common_pool);
 }
 
 
@@ -303,14 +320,11 @@ fs_upgrade(svn_fs_t *fs,
            void *notify_baton,
            svn_cancel_func_t cancel_func,
            void *cancel_baton,
+           svn_mutex__t *common_pool_lock,
            apr_pool_t *pool,
            apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_fs__open(fs, path, pool));
-  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
-  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_fs__upgrade(fs, notify_func, notify_baton,
                             cancel_func, cancel_baton, pool);
 }
@@ -323,14 +337,11 @@ fs_verify(svn_fs_t *fs, const char *path
           void *notify_baton,
           svn_cancel_func_t cancel_func,
           void *cancel_baton,
+          svn_mutex__t *common_pool_lock,
           apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_fs__open(fs, path, pool));
-  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
-  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_fs__verify(fs, start, end, notify_func, notify_baton,
                            cancel_func, cancel_baton, pool);
 }
@@ -342,14 +353,11 @@ fs_pack(svn_fs_t *fs,
         void *notify_baton,
         svn_cancel_func_t cancel_func,
         void *cancel_baton,
+        svn_mutex__t *common_pool_lock,
         apr_pool_t *pool,
         apr_pool_t *common_pool)
 {
-  SVN_ERR(svn_fs__check_fs(fs, FALSE));
-  SVN_ERR(initialize_fs_struct(fs));
-  SVN_ERR(svn_fs_fs__open(fs, path, pool));
-  SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
-  SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+  SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
   return svn_fs_fs__pack(fs, notify_func, notify_baton,
                          cancel_func, cancel_baton, pool);
 }

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/fs.h Tue Oct 15 23:44:41 2013
@@ -167,6 +167,9 @@ extern "C" {
 /* The minimum format number that supports packed revprops. */
 #define SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT 7
 
+/* Minimum format number that will record moves */
+#define SVN_FS_FS__MIN_MOVE_SUPPORT_FORMAT 7
+
 /* The minimum format number that supports a configuration file (fsfs.conf) */
 #define SVN_FS_FS__MIN_CONFIG_FILE 4
 

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/hotcopy.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/hotcopy.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.c Tue Oct 15 23:44:41 2013
@@ -50,6 +50,8 @@
 #define ACTION_DELETE      "delete"
 #define ACTION_REPLACE     "replace"
 #define ACTION_RESET       "reset"
+#define ACTION_MOVE        "move"
+#define ACTION_MOVEREPLACE "movereplace"
 
 /* True and False flags. */
 #define FLAG_TRUE          "true"
@@ -239,6 +241,14 @@ read_change(change_t **change_p,
     {
       info->change_kind = svn_fs_path_change_reset;
     }
+  else if (strcmp(str, ACTION_MOVE) == 0)
+    {
+      info->change_kind = svn_fs_path_change_move;
+    }
+  else if (strcmp(str, ACTION_MOVEREPLACE) == 0)
+    {
+      info->change_kind = svn_fs_path_change_movereplace;
+    }
   else
     {
       return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -350,9 +360,11 @@ write_change_entry(svn_stream_t *stream,
                    svn_boolean_t include_node_kind,
                    apr_pool_t *pool)
 {
-  const char *idstr, *buf;
+  const char *idstr;
   const char *change_string = NULL;
   const char *kind_string = "";
+  svn_stringbuf_t *buf;
+  apr_size_t len;
 
   switch (change->change_kind)
     {
@@ -371,6 +383,12 @@ write_change_entry(svn_stream_t *stream,
     case svn_fs_path_change_reset:
       change_string = ACTION_RESET;
       break;
+    case svn_fs_path_change_move:
+      change_string = ACTION_MOVE;
+      break;
+    case svn_fs_path_change_movereplace:
+      change_string = ACTION_MOVEREPLACE;
+      break;
     default:
       return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                _("Invalid change type %d"),
@@ -391,22 +409,24 @@ write_change_entry(svn_stream_t *stream,
                                  ? SVN_FS_FS__KIND_DIR
                                   : SVN_FS_FS__KIND_FILE);
     }
-  buf = apr_psprintf(pool, "%s %s%s %s %s %s\n",
-                     idstr, change_string, kind_string,
-                     change->text_mod ? FLAG_TRUE : FLAG_FALSE,
-                     change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
-                     path);
-
-  SVN_ERR(svn_stream_puts(stream, buf));
+  buf = svn_stringbuf_createf(pool, "%s %s%s %s %s %s\n",
+                              idstr, change_string, kind_string,
+                              change->text_mod ? FLAG_TRUE : FLAG_FALSE,
+                              change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
+                              path);
 
   if (SVN_IS_VALID_REVNUM(change->copyfrom_rev))
     {
-      buf = apr_psprintf(pool, "%ld %s", change->copyfrom_rev,
-                         change->copyfrom_path);
-      SVN_ERR(svn_stream_puts(stream, buf));
+      svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s",
+                                                 change->copyfrom_rev,
+                                                 change->copyfrom_path));
     }
 
-  return svn_error_trace(svn_stream_puts(stream, "\n"));
+   svn_stringbuf_appendbyte(buf, '\n');
+
+   /* Write all change info in one write call. */
+   len = buf->len;
+   return svn_error_trace(svn_stream_write(stream, buf->data, &len));
 }
 
 svn_error_t *

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/low_level.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/pack.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/pack.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/recovery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/recovery.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/revprops.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/revprops.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.c Tue Oct 15 23:44:41 2013
@@ -599,6 +599,33 @@ unparse_dir_entries(apr_hash_t **str_ent
   return SVN_NO_ERROR;
 }
 
+/* Copy the contents of NEW_CHANGE into OLD_CHANGE assuming that both
+   belong to the same path.  Allocate copies in POOL.
+ */
+static void
+replace_change(svn_fs_path_change2_t *old_change,
+               const svn_fs_path_change2_t *new_change,
+               apr_pool_t *pool)
+{
+  /* An add at this point must be following a previous delete,
+      so treat it just like a replace. */
+  old_change->node_kind = new_change->node_kind;
+  old_change->node_rev_id = svn_fs_fs__id_copy(new_change->node_rev_id,
+                                               pool);
+  old_change->text_mod = new_change->text_mod;
+  old_change->prop_mod = new_change->prop_mod;
+  if (new_change->copyfrom_rev == SVN_INVALID_REVNUM)
+    {
+      old_change->copyfrom_rev = SVN_INVALID_REVNUM;
+      old_change->copyfrom_path = NULL;
+    }
+  else
+    {
+      old_change->copyfrom_rev = new_change->copyfrom_rev;
+      old_change->copyfrom_path = apr_pstrdup(pool,
+                                              new_change->copyfrom_path);
+    }
+}
 
 /* Merge the internal-use-only CHANGE into a hash of public-FS
    svn_fs_path_change2_t CHANGES, collapsing multiple changes into a
@@ -637,11 +664,13 @@ fold_change(apr_hash_t *changes,
            _("Invalid change ordering: new node revision ID "
              "without delete"));
 
-      /* Sanity check: an add, replacement, or reset must be the first
+      /* Sanity check: an add, replacement, move, or reset must be the first
          thing to follow a deletion. */
       if ((old_change->change_kind == svn_fs_path_change_delete)
           && (! ((info->change_kind == svn_fs_path_change_replace)
                  || (info->change_kind == svn_fs_path_change_reset)
+                 || (info->change_kind == svn_fs_path_change_movereplace)
+                 || (info->change_kind == svn_fs_path_change_move)
                  || (info->change_kind == svn_fs_path_change_add))))
         return svn_error_create
           (SVN_ERR_FS_CORRUPT, NULL,
@@ -649,7 +678,8 @@ fold_change(apr_hash_t *changes,
 
       /* Sanity check: an add can't follow anything except
          a delete or reset.  */
-      if ((info->change_kind == svn_fs_path_change_add)
+      if ((   (info->change_kind == svn_fs_path_change_add)
+           || (info->change_kind == svn_fs_path_change_move))
           && (old_change->change_kind != svn_fs_path_change_delete)
           && (old_change->change_kind != svn_fs_path_change_reset))
         return svn_error_create
@@ -666,7 +696,8 @@ fold_change(apr_hash_t *changes,
           break;
 
         case svn_fs_path_change_delete:
-          if (old_change->change_kind == svn_fs_path_change_add)
+          if ((old_change->change_kind == svn_fs_path_change_add)
+              || (old_change->change_kind == svn_fs_path_change_move))
             {
               /* If the path was introduced in this transaction via an
                  add, and we are deleting it, just remove the path
@@ -688,22 +719,16 @@ fold_change(apr_hash_t *changes,
         case svn_fs_path_change_replace:
           /* An add at this point must be following a previous delete,
              so treat it just like a replace. */
+          replace_change(old_change, info, pool);
           old_change->change_kind = svn_fs_path_change_replace;
-          old_change->node_rev_id = svn_fs_fs__id_copy(info->node_rev_id,
-                                                       pool);
-          old_change->text_mod = info->text_mod;
-          old_change->prop_mod = info->prop_mod;
-          if (info->copyfrom_rev == SVN_INVALID_REVNUM)
-            {
-              old_change->copyfrom_rev = SVN_INVALID_REVNUM;
-              old_change->copyfrom_path = NULL;
-            }
-          else
-            {
-              old_change->copyfrom_rev = info->copyfrom_rev;
-              old_change->copyfrom_path = apr_pstrdup(pool,
-                                                      info->copyfrom_path);
-            }
+          break;
+
+        case svn_fs_path_change_move:
+        case svn_fs_path_change_movereplace:
+          /* A move at this point must be following a previous delete,
+             so treat it just like a replacing move. */
+          replace_change(old_change, info, pool);
+          old_change->change_kind = svn_fs_path_change_movereplace;
           break;
 
         case svn_fs_path_change_modify:
@@ -769,7 +794,8 @@ process_changes(apr_hash_t *changed_path
       */
 
       if ((change->info.change_kind == svn_fs_path_change_delete)
-           || (change->info.change_kind == svn_fs_path_change_replace))
+           || (change->info.change_kind == svn_fs_path_change_replace)
+           || (change->info.change_kind == svn_fs_path_change_movereplace))
         {
           apr_hash_index_t *hi;
 
@@ -1519,9 +1545,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
   svn_fs_path_change2_t *change;
   apr_hash_t *changes = apr_hash_make(pool);
 
+  /* Not using APR_BUFFERED to append change in one atomic write operation. */
   SVN_ERR(svn_io_file_open(&file, path_txn_changes(fs, txn_id, pool),
-                           APR_APPEND | APR_WRITE | APR_CREATE
-                           | APR_BUFFERED, APR_OS_DEFAULT, pool));
+                           APR_APPEND | APR_WRITE | APR_CREATE,
+                           APR_OS_DEFAULT, pool));
 
   change = svn_fs__path_change_create_internal(id, change_kind, pool);
   change->text_mod = text_mod;
@@ -2931,27 +2958,40 @@ write_final_rev(const svn_fs_id_t **new_
   return SVN_NO_ERROR;
 }
 
-/* Write the changed path info from transaction TXN_ID in filesystem FS to
-   the permanent rev-file FILE.  *OFFSET_P is set the to offset in the
-   file of the beginning of this information.  NEW_REV is the revision
-   currently being committed.  Perform temporary allocations in POOL. */
+/* Write the changed path info CHANGED_PATHS from transaction TXN_ID to the
+   permanent rev-file FILE representing NEW_REV in filesystem FS.  *OFFSET_P
+   is set the to offset in the file of the beginning of this information.
+   NEW_REV is the revision currently being committed.
+   Perform temporary allocations in POOL. */
 static svn_error_t *
 write_final_changed_path_info(apr_off_t *offset_p,
                               apr_file_t *file,
                               svn_fs_t *fs,
                               const svn_fs_fs__id_part_t *txn_id,
+                              apr_hash_t *changed_paths,
                               svn_revnum_t new_rev,
                               apr_pool_t *pool)
 {
-  apr_hash_t *changed_paths;
   apr_off_t offset;
   svn_stream_t *stream;
   svn_checksum_ctx_t *fnv1a_checksum_ctx;
+  apr_hash_index_t *hi;
 
   SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
 
-  SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, fs, txn_id, pool));
+  /* all moves specify the "copy-from-rev" as REV-1 */
+  if (svn_fs_fs__supports_move(fs))
+    for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+      {
+        svn_fs_path_change2_t *change;
+        apr_hash_this(hi, NULL, NULL, (void **)&change);
+
+        if (   (change->change_kind == svn_fs_path_change_move)
+            || (change->change_kind == svn_fs_path_change_movereplace))
+          change->copyfrom_rev = new_rev - 1;
+      }
 
+  /* write to target file & calculate checksum */
   stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
                              svn_stream_from_aprfile2(file, TRUE, pool),
                              pool);
@@ -3131,6 +3171,169 @@ verify_locks(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* If CHANGE is move, verify that there is no other move with the same
+   copy-from path in SOURCE_PATHS already (parent or sub-node moves are fine).
+   Add the source path to SOURCE_PATHS after successful verification.
+   Allocate the hashed strings in POOL. */
+static svn_error_t *
+check_for_duplicate_move_source(apr_hash_t *source_paths,
+                                change_t *change,
+                                apr_pool_t *pool)
+{
+  if (   change->info.change_kind == svn_fs_path_change_move
+      || change->info.change_kind == svn_fs_path_change_movereplace)
+    if (change->info.copyfrom_path)
+      {
+        apr_size_t len = strlen(change->info.copyfrom_path);
+        if (apr_hash_get(source_paths, change->info.copyfrom_path, len))
+          return svn_error_createf(SVN_ERR_FS_AMBIGUOUS_MOVE, NULL,
+                      _("Path '%s' has been moved to more than one target"),
+                                   change->info.copyfrom_path);
+
+        apr_hash_set(source_paths,
+                     apr_pstrmemdup(pool, change->info.copyfrom_path, len),
+                     len,
+                     change->info.copyfrom_path);
+      }
+
+  return SVN_NO_ERROR;
+}
+
+/* Verify that the moves we are about to commit with TXN_ID in FS are unique
+   and the respective copy sources have been deleted.  OLD_REV is the last
+   committed revision.  CHANGED_PATHS is the list of changes paths in this
+   txn.  Use POOL for temporary allocations. */
+static svn_error_t *
+verify_moves(svn_fs_t *fs,
+             const svn_fs_fs__id_part_t *txn_id,
+             svn_revnum_t old_rev,
+             apr_hash_t *changed_paths,
+             apr_pool_t *pool)
+{
+  apr_hash_t *source_paths = apr_hash_make(pool);
+  svn_revnum_t revision;
+  apr_pool_t *iter_pool = svn_pool_create(pool);
+  apr_hash_index_t *hi;
+  int i;
+  apr_array_header_t *moves
+    = apr_array_make(pool, 16, sizeof(svn_sort__item_t));
+  apr_array_header_t *deletions
+    = apr_array_make(pool, 16, sizeof(const char *));
+
+  /* extract moves and deletions from the current txn's change list */
+
+  for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+    {
+      const char *path;
+      apr_ssize_t len;
+      change_t *change;
+      apr_hash_this(hi, (const void**)&path, &len, (void**)&change);
+
+      if (   change->info.copyfrom_path
+          && (   change->info.change_kind == svn_fs_path_change_move
+              || change->info.change_kind == svn_fs_path_change_movereplace))
+        {
+          svn_sort__item_t *item = apr_array_push(moves);
+          item->key = path;
+          item->klen = len;
+          item->value = change;
+        }
+
+      if (   change->info.change_kind == svn_fs_path_change_delete
+          || change->info.change_kind == svn_fs_path_change_replace
+          || change->info.change_kind == svn_fs_path_change_movereplace)
+        APR_ARRAY_PUSH(deletions, const char *) = path;
+    }
+
+  /* no moves? -> done here */
+
+  if (moves->nelts == 0)
+    return SVN_NO_ERROR;
+
+  /* correct the deletions that refer to moved paths and make them refer to
+     the paths in OLD_REV */
+
+  qsort(moves->elts, moves->nelts, moves->elt_size,
+        svn_sort_compare_paths);
+
+  for (i = 0; i < deletions->nelts; ++i)
+    {
+      const char *deleted_path = APR_ARRAY_IDX(deletions, i, const char*);
+      int closest_move_idx
+        = svn_sort__bsearch_lower_bound(deleted_path, moves,
+                                        svn_sort_compare_paths);
+
+      if (closest_move_idx < moves->nelts)
+        {
+          svn_sort__item_t *closest_move_item
+            = &APR_ARRAY_IDX(moves, closest_move_idx, svn_sort__item_t);
+          const char *relpath
+            = svn_dirent_skip_ancestor(closest_move_item->key,
+                                       deleted_path);
+          if (relpath)
+            {
+              change_t *closed_move = closest_move_item->value;
+              APR_ARRAY_IDX(deletions, i, const char*)
+                = svn_dirent_join(closed_move->info.copyfrom_path, relpath,
+                                  pool);
+            }
+        }
+    }
+
+  qsort(deletions->elts, deletions->nelts, deletions->elt_size,
+        svn_sort_compare_paths);
+
+  /* The _same_ source paths must never occur more than once in any move 
+     since our base revision. */
+
+  for (i = 0; moves->nelts; ++i)
+    SVN_ERR(check_for_duplicate_move_source (source_paths,
+                          APR_ARRAY_IDX(moves, i, svn_sort__item_t).value,
+                          pool));
+
+  for (revision = txn_id->revision + 1; revision <= old_rev; ++revision)
+    {
+      apr_array_header_t *changes;
+      change_t **changes_p;
+
+      svn_pool_clear(iter_pool);
+      svn_fs_fs__get_changes(&changes, fs, revision, iter_pool);
+
+      changes_p = (change_t **)&changes->elts;
+      for (i = 0; i < changes->nelts; ++i)
+        SVN_ERR(check_for_duplicate_move_source(source_paths, changes_p[i],
+                                                pool));
+    }
+
+  /* The move source paths must been deleted in this txn. */
+
+  for (i = 0; i < moves->nelts; ++i)
+    {
+      change_t *change = APR_ARRAY_IDX(moves, i, svn_sort__item_t).value;
+
+      /* there must be a deletion of move's copy-from path
+         (or any of its parents) */
+
+      int closest_deletion_idx
+        = svn_sort__bsearch_lower_bound(change->info.copyfrom_path, deletions,
+                                        svn_sort_compare_paths);
+      if (closest_deletion_idx < deletions->nelts)
+        {
+          const char *closest_deleted_path
+            = APR_ARRAY_IDX(deletions, closest_deletion_idx, const char *);
+          if (!svn_dirent_is_ancestor(closest_deleted_path,
+                                      change->info.copyfrom_path))
+            return svn_error_createf(SVN_ERR_FS_INCOMPLETE_MOVE, NULL,
+                        _("Path '%s' has been moved without being deleted"),
+                                     change->info.copyfrom_path);
+        }
+    }
+
+  svn_pool_destroy(iter_pool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton used for commit_body below. */
 struct commit_baton {
   svn_revnum_t *new_rev_p;
@@ -3163,6 +3366,7 @@ commit_body(void *baton, apr_pool_t *poo
   apr_array_header_t *txnprop_list;
   svn_prop_t prop;
   const svn_fs_fs__id_part_t *txn_id = svn_fs_fs__txn_get_id(cb->txn);
+  apr_hash_t *changed_paths;
 
   /* Get the current youngest revision. */
   SVN_ERR(svn_fs_fs__youngest_rev(&old_rev, cb->fs, pool));
@@ -3179,6 +3383,16 @@ commit_body(void *baton, apr_pool_t *poo
      discovered locks. */
   SVN_ERR(verify_locks(cb->fs, txn_id, pool));
 
+  /* we need the changes list for verification as well as for writing it
+     to the final rev file */
+  SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
+                                       pool));
+
+  /* ensure that no change in this txn or any txn committed since the start
+   * of this txn violates our move semantics */
+  if (svn_fs_fs__supports_move(cb->fs))
+    SVN_ERR(verify_moves(cb->fs, txn_id, old_rev, changed_paths, pool));
+
   /* Get the next node_id and copy_id to use. */
   if (ffd->format < SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT)
     SVN_ERR(get_next_revision_ids(&start_node_id, &start_copy_id, cb->fs,
@@ -3210,7 +3424,8 @@ commit_body(void *baton, apr_pool_t *poo
 
   /* Write the changed-path information. */
   SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
-                                        cb->fs, txn_id, new_rev, pool));
+                                        cb->fs, txn_id, changed_paths,
+                                        new_rev, pool));
 
   if (!svn_fs_fs__use_log_addressing(cb->fs, new_rev))
     {

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.h Tue Oct 15 23:44:41 2013
@@ -280,4 +280,4 @@ svn_fs_fs__begin_txn(svn_fs_txn_t **txn_
                      apr_uint32_t flags,
                      apr_pool_t *pool);
 
-#endif
\ No newline at end of file
+#endif

Propchange: subversion/branches/log-addressing/subversion/libsvn_fs_fs/transaction.h
------------------------------------------------------------------------------
    svn:eol-style = native