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 2010/09/26 13:59:01 UTC

svn commit: r1001417 [6/7] - in /subversion/branches/performance: ./ build/ notes/ notes/http-and-webdav/ subversion/bindings/javahl/native/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/tigris/subv...

Modified: subversion/branches/performance/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/main.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/main.c (original)
+++ subversion/branches/performance/subversion/svn/main.c Sun Sep 26 11:58:58 2010
@@ -2087,12 +2087,24 @@ main(int argc, const char *argv[])
         }
     }
 
-  if (opt_state.relocate && (opt_state.depth != svn_depth_unknown))
+  /* Relocation is infinite-depth only. */
+  if (opt_state.relocate)
     {
-      err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
-                             _("--relocate and --depth are mutually "
-                               "exclusive"));
-      return svn_cmdline_handle_exit_error(err, pool, "svn: ");
+      if (opt_state.depth != svn_depth_unknown)
+        {
+          err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                                 _("--relocate and --depth are mutually "
+                                   "exclusive"));
+          return svn_cmdline_handle_exit_error(err, pool, "svn: ");
+        }
+      if (! descend)
+        {
+          err = svn_error_create(
+                    SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+                    _("--relocate and --non-recursive (-N) are mutually "
+                      "exclusive"));
+          return svn_cmdline_handle_exit_error(err, pool, "svn: ");
+        }
     }
 
   /* Only a few commands can accept a revision range; the rest can take at

Modified: subversion/branches/performance/subversion/svn/switch-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/switch-cmd.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/switch-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/switch-cmd.c Sun Sep 26 11:58:58 2010
@@ -41,7 +41,6 @@
 
 static svn_error_t *
 rewrite_urls(const apr_array_header_t *targets,
-             svn_boolean_t recurse,
              svn_client_ctx_t *ctx,
              apr_pool_t *pool)
 {
@@ -67,7 +66,7 @@ rewrite_urls(const apr_array_header_t *t
 
   if (targets->nelts == 2)
     {
-      SVN_ERR(svn_client_relocate("", from, to, recurse, ctx, pool));
+      SVN_ERR(svn_client_relocate2("", from, to, ctx, pool));
     }
   else
     {
@@ -75,8 +74,7 @@ rewrite_urls(const apr_array_header_t *t
         {
           const char *target = APR_ARRAY_IDX(targets, i, const char *);
           svn_pool_clear(subpool);
-          SVN_ERR(svn_client_relocate(target, from, to, recurse,
-                                      ctx, subpool));
+          SVN_ERR(svn_client_relocate2(target, from, to, ctx, subpool));
         }
     }
 
@@ -109,9 +107,7 @@ svn_cl__switch(apr_getopt_t *os,
 
   /* handle only-rewrite case specially */
   if (opt_state->relocate)
-    return rewrite_urls(targets,
-                        SVN_DEPTH_IS_RECURSIVE(opt_state->depth),
-                        ctx, scratch_pool);
+    return rewrite_urls(targets, ctx, scratch_pool);
 
   if (targets->nelts < 1)
     return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

Modified: subversion/branches/performance/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnrdump/dump_editor.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/performance/subversion/svnrdump/dump_editor.c Sun Sep 26 11:58:58 2010
@@ -27,6 +27,7 @@
 #include "svn_repos.h"
 #include "svn_path.h"
 #include "svn_props.h"
+#include "svn_subst.h"
 #include "svn_dirent_uri.h"
 
 #include "dump_editor.h"
@@ -66,11 +67,41 @@ struct dump_edit_baton {
   const char *base_checksum;
 
   /* Flags to trigger dumping props and text */
-  svn_boolean_t dump_props;
   svn_boolean_t dump_text;
-  svn_boolean_t dump_props_pending;
+  svn_boolean_t dump_props;
+  svn_boolean_t dump_newlines;
 };
 
+/* Normalize the line ending style of the values of properties in PROPS
+ * that "need translation" (according to svn_prop_needs_translation(),
+ * currently all svn:* props) so that they contain only LF (\n) line endings.
+ */
+svn_error_t *
+normalize_props(apr_hash_t *props,
+                apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  const char *key, *cstring;
+  const svn_string_t *value;
+
+  for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
+    {
+      key = svn__apr_hash_index_key(hi);
+      value = svn__apr_hash_index_val(hi);
+
+      if (svn_prop_needs_translation(key))
+        {
+          SVN_ERR(svn_subst_translate_cstring2(value->data, &cstring,
+                                               "\n", TRUE,
+                                               NULL, FALSE,
+                                               pool));
+          value = svn_string_create(cstring, pool);
+          apr_hash_set(props, key, APR_HASH_KEY_STRING, value);
+        }
+    }
+  return SVN_NO_ERROR;
+}
+
 /* Make a directory baton to represent the directory at path (relative
  * to the edit_baton).
  *
@@ -97,17 +128,15 @@ make_dir_baton(const char *path,
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *abspath;
 
-  /* Disallow a path relative to nothing. */
-  SVN_ERR_ASSERT_NO_RETURN(!path || pb);
-
   /* Construct the full path of this node. */
   if (pb)
     abspath = svn_uri_join("/", path, pool);
   else
-    abspath = "/";
+    abspath = apr_pstrdup(pool, "/");
 
-  /* Remove leading slashes from copyfrom paths. */
-  if (copyfrom_path && strcmp(copyfrom_path, "/"))
+  /* Strip leading slash from copyfrom_path so that the path is
+     canonical and svn_relpath_join can be used */
+  if (copyfrom_path)
     copyfrom_path = ((*copyfrom_path == '/') ?
                      copyfrom_path + 1 : copyfrom_path);
 
@@ -139,6 +168,7 @@ dump_props(struct dump_edit_baton *eb,
   if (trigger_var && !*trigger_var)
     return SVN_NO_ERROR;
 
+  SVN_ERR(normalize_props(eb->props, eb->pool));
   svn_stringbuf_setempty(eb->propstring);
   propstream = svn_stream_from_stringbuf(eb->propstring, eb->pool);
   SVN_ERR(svn_hash_write_incremental(eb->props, eb->deleted_props,
@@ -172,8 +202,8 @@ dump_props(struct dump_edit_baton *eb,
       SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
 
       /* Cleanup so that data is never dumped twice. */
-      svn_hash__clear(eb->props, pool);
-      svn_hash__clear(eb->deleted_props, pool);
+      svn_hash__clear(eb->props, eb->pool);
+      svn_hash__clear(eb->deleted_props, eb->pool);
       if (trigger_var)
         *trigger_var = FALSE;
     }
@@ -181,6 +211,19 @@ dump_props(struct dump_edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+dump_newlines(struct dump_edit_baton *eb,
+           svn_boolean_t *trigger_var,
+           apr_pool_t *pool)
+{
+  if (trigger_var && *trigger_var)
+    {
+      SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+      *trigger_var = FALSE;
+    }
+  return SVN_NO_ERROR;
+}
+
 /*
  * Write out a node record for PATH of type KIND under EB->FS_ROOT.
  * ACTION describes what is happening to the node (see enum
@@ -227,6 +270,9 @@ dump_node(struct dump_edit_baton *eb,
   switch (action)
     {
     case svn_node_action_change:
+      /* We are here after a change_file_prop or change_dir_prop. They
+         set up whatever dump_props they needed to- nothing to
+         do here but print node action information */
       SVN_ERR(svn_stream_printf(eb->stream, pool,
                                 SVN_REPOS_DUMPFILE_NODE_ACTION
                                 ": change\n"));
@@ -240,7 +286,9 @@ dump_node(struct dump_edit_baton *eb,
                                     SVN_REPOS_DUMPFILE_NODE_ACTION
                                     ": replace\n"));
 
-          eb->dump_props_pending = TRUE;
+          /* Wait for a change_*_prop to be called before dumping
+             anything */          
+          eb->dump_props = TRUE;
           break;
         }
       /* More complex case: is_copy is true, and copyfrom_path/
@@ -257,7 +305,6 @@ dump_node(struct dump_edit_baton *eb,
 
       /* We can leave this routine quietly now, don't need to dump any
          content; that was already done in the second record. */
-      eb->dump_props = FALSE;
       break;
 
     case svn_node_action_delete:
@@ -265,10 +312,10 @@ dump_node(struct dump_edit_baton *eb,
                                 SVN_REPOS_DUMPFILE_NODE_ACTION
                                 ": delete\n"));
 
-      /* We can leave this routine quietly now, don't need to dump
-         any content. */
+      /* We can leave this routine quietly now. Nothing more to do-
+         print a couple of newlines because we're not dumping props or
+         text. */      
       SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
-      eb->dump_props = FALSE;
       break;
 
     case svn_node_action_add:
@@ -277,15 +324,17 @@ dump_node(struct dump_edit_baton *eb,
 
       if (!is_copy)
         {
-          /* eb->dump_props_pending for files is handled in close_file
+          /* eb->dump_props for files is handled in close_file
              which is called immediately.  However, directories are not
              closed until all the work inside them has been done;
-             eb->dump_props_pending for directories is handled in all the
+             eb->dump_props for directories is handled in all the
              functions that can possibly be called after add_directory:
              add_directory, open_directory, delete_entry, close_directory,
              add_file, open_file. change_dir_prop is a special case. */
 
-          eb->dump_props_pending = TRUE;
+          /* Wait for a change_*_prop to be called before dumping
+             anything */          
+          eb->dump_props = TRUE;
           break;
         }
 
@@ -296,19 +345,18 @@ dump_node(struct dump_edit_baton *eb,
                                 ": %s\n",
                                 copyfrom_rev, copyfrom_path));
 
-      /* Ugly hack: If a directory was copied from a previous revision,
-         nothing else can be done, and close_file won't be called to
-         write two blank lines. Write them here otherwise the `svnadmin
-         load` parser will fail. */
+      /* Ugly hack: If a directory was copied from a previous
+         revision, nothing like close_file will be called to write two
+         blank lines. If change_dir_prop is called, props are dumped
+         (along with the necessary PROPS-END\n\n and we're good. So
+         set a dump_newlines here to print the newlines unless
+         change_dir_prop is called next otherwise the `svnadmin load`
+         parser will fail.  */ 
       if (kind == svn_node_dir)
-        SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+        eb->dump_newlines = TRUE;
 
       break;
     }
-
-  /* Dump property headers */
-  SVN_ERR(dump_props(eb, &(eb->dump_props), FALSE, pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -345,11 +393,15 @@ delete_entry(const char *path,
   LDR_DBG(("delete_entry %s\n", path));
 
   /* Some pending properties to dump? */
-  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(pb->eb, &(pb->eb->dump_newlines), pool));
 
   /* Add this path to the deleted_entries of the parent directory
      baton. */
-  apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, pb);
+  apr_hash_set(pb->deleted_entries, apr_pstrdup(pb->eb->pool, path),
+               APR_HASH_KEY_STRING, pb);
 
   return SVN_NO_ERROR;
 }
@@ -371,7 +423,10 @@ add_directory(const char *path,
   LDR_DBG(("add_directory %s\n", path));
 
   /* Some pending properties to dump? */
-  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(pb->eb, &(pb->eb->dump_newlines), pool));
 
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
@@ -413,7 +468,10 @@ open_directory(const char *path,
   LDR_DBG(("open_directory %s\n", path));
 
   /* Some pending properties to dump? */
-  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(pb->eb, &(pb->eb->dump_newlines), pool));
 
   /* If the parent directory has explicit comparison path and rev,
      record the same for this one. */
@@ -442,12 +500,15 @@ close_directory(void *dir_baton,
 
   LDR_DBG(("close_directory %p\n", dir_baton));
 
+  /* Some pending properties to dump? */
+  SVN_ERR(dump_props(eb, &(eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(eb, &(eb->dump_newlines), pool));
+
   /* Create a pool just for iterations to allocate a loop variable */
   iterpool = svn_pool_create(pool);
 
-  /* Some pending properties to dump? */
-  SVN_ERR(dump_props(eb, &(eb->dump_props_pending), TRUE, pool));
-
   /* Dump the deleted directory entries */
   for (hi = apr_hash_first(iterpool, db->deleted_entries); hi;
        hi = apr_hash_next(hi))
@@ -481,7 +542,10 @@ add_file(const char *path,
   LDR_DBG(("add_file %s\n", path));
 
   /* Some pending properties to dump? */
-  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(pb->eb, &(pb->eb->dump_newlines), pool));
 
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
@@ -523,7 +587,10 @@ open_file(const char *path,
   LDR_DBG(("open_file %s\n", path));
 
   /* Some pending properties to dump? */
-  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+  SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props), TRUE, pool));
+
+  /* Some pending newlines to dump? */
+  SVN_ERR(dump_newlines(pb->eb, &(pb->eb->dump_newlines), pool));
 
   /* If the parent directory has explicit copyfrom path and rev,
      record the same for this one. */
@@ -558,8 +625,8 @@ change_dir_prop(void *parent_baton,
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(db->eb->props, apr_pstrdup(pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, pool));
+    apr_hash_set(db->eb->props, apr_pstrdup(db->eb->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, db->eb->pool));
   else
     apr_hash_set(db->eb->deleted_props, apr_pstrdup(pool, name),
                  APR_HASH_KEY_STRING, "");
@@ -568,17 +635,21 @@ change_dir_prop(void *parent_baton,
     {
       /* If db->written_out is set, it means that the node information
          corresponding to this directory has already been written: don't
-         do anything; dump_props_pending will take care of dumping the
+         do anything; dump_props will take care of dumping the
          props. If it not, dump the node itself before dumping the
          props. */
 
       SVN_ERR(dump_node(db->eb, db->abspath, svn_node_dir,
                         svn_node_action_change, FALSE, db->copyfrom_path,
                         db->copyfrom_rev, pool));
-
-      SVN_ERR(dump_props(db->eb, NULL, TRUE, pool));
       db->written_out = TRUE;
     }
+
+  /* Dump props whether or not the directory has been written
+     out. Then disable printing a couple of extra newlines */
+  SVN_ERR(dump_props(db->eb, NULL, TRUE, pool));
+  db->eb->dump_newlines = FALSE;
+
   return SVN_NO_ERROR;
 }
 
@@ -596,16 +667,16 @@ change_file_prop(void *file_baton,
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(eb->props, apr_pstrdup(pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, pool));
+    apr_hash_set(eb->props, apr_pstrdup(eb->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, eb->pool));
   else
-    apr_hash_set(eb->deleted_props, apr_pstrdup(pool, name),
+    apr_hash_set(eb->deleted_props, apr_pstrdup(eb->pool, name),
                  APR_HASH_KEY_STRING, "");
 
   /* Dump the property headers and wait; close_file might need
      to write text headers too depending on whether
      apply_textdelta is called */
-  eb->dump_props_pending = TRUE;
+  eb->dump_props = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -680,11 +751,11 @@ close_file(void *file_baton,
 
   LDR_DBG(("close_file %p\n", file_baton));
 
-  /* Some pending properties to dump? */
-  SVN_ERR(dump_props(eb, &(eb->dump_props_pending), FALSE, pool));
+  /* Some pending properties to dump? Dump just the headers- dump the
+     props only after dumping the text headers too (if present) */
+  SVN_ERR(dump_props(eb, &(eb->dump_props), FALSE, pool));
 
-  /* The prop headers have already been dumped in dump_node; now dump
-     the text headers. */
+  /* Dump the text headers */
   if (eb->dump_text)
     {
       /* Text-delta: true */
@@ -716,7 +787,7 @@ close_file(void *file_baton,
 
   /* Content-length: 1549 */
   /* If both text and props are absent, skip this header */
-  if (eb->dump_props || eb->dump_props_pending)
+  if (eb->dump_props)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                               ": %ld\n\n",
@@ -727,17 +798,16 @@ close_file(void *file_baton,
                               ": %ld\n\n",
                               (unsigned long)info->size));
 
-  /* Dump the props; the propstring should have already been
-     written in dump_node or above */
-  if (eb->dump_props || eb->dump_props_pending)
+  /* Dump the props now */
+  if (eb->dump_props)
     {
       SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
                                &(eb->propstring->len)));
 
       /* Cleanup */
-      eb->dump_props = eb->dump_props_pending = FALSE;
-      svn_hash__clear(eb->props, pool);
-      svn_hash__clear(eb->deleted_props, pool);
+      eb->dump_props = FALSE;
+      svn_hash__clear(eb->props, eb->pool);
+      svn_hash__clear(eb->deleted_props, eb->pool);
     }
 
   /* Dump the text */
@@ -758,6 +828,8 @@ close_file(void *file_baton,
       eb->dump_text = FALSE;
     }
 
+  /* Write a couple of blank lines for matching output with `svnadmin
+     dump` */
   SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/performance/subversion/svnrdump/dump_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnrdump/dump_editor.h?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnrdump/dump_editor.h (original)
+++ subversion/branches/performance/subversion/svnrdump/dump_editor.h Sun Sep 26 11:58:58 2010
@@ -87,4 +87,12 @@ get_dump_editor(const svn_delta_editor_t
                 svn_stream_t *stream,
                 apr_pool_t *pool);
 
+/**
+ * Normalize the line ending style of the values of properties in @a
+ * rev_props using @a pool for memory allocation.
+ */
+svn_error_t *
+normalize_props(apr_hash_t *props,
+                apr_pool_t *pool);
+
 #endif

Modified: subversion/branches/performance/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnrdump/load_editor.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/performance/subversion/svnrdump/load_editor.c Sun Sep 26 11:58:58 2010
@@ -56,6 +56,12 @@ commit_callback(const svn_commit_info_t 
   return SVN_NO_ERROR;
 }
 
+/* See subversion/svnsync/main.c for docstring */
+static svn_boolean_t is_atomicity_error(svn_error_t *err)
+{
+  return svn_error_has_cause(err, SVN_ERR_FS_PROP_BASEVALUE_MISMATCH);
+}
+
 /* Acquire a lock (of sorts) on the repository associated with the
  * given RA SESSION. This lock is just a revprop change attempt in a
  * time-delay loop. This function is duplicated by svnsync in main.c.
@@ -65,14 +71,36 @@ commit_callback(const svn_commit_info_t 
  * applications to avoid duplication.
  */
 static svn_error_t *
-get_lock(svn_ra_session_t *session, apr_pool_t *pool)
+get_lock(const svn_string_t **lock_string_p,
+         svn_ra_session_t *session,
+         apr_pool_t *pool)
 {
   char hostname_str[APRMAXHOSTLEN + 1] = { 0 };
   svn_string_t *mylocktoken, *reposlocktoken;
   apr_status_t apr_err;
+  svn_boolean_t be_atomic;
   apr_pool_t *subpool;
   int i;
 
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
+  if (! be_atomic)
+    {
+      /* Pre-1.7 server.  Can't lock without a race condition.
+         See issue #3546.
+       */
+      svn_error_t *err;
+
+      err = svn_error_create(
+              SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+              _("Target server does not support atomic revision property "
+                "edits; consider upgrading it to 1.7 or using an external "
+                "locking program"));
+      svn_handle_warning2(stderr, err, "svnrdump: ");
+      svn_error_clear(err);
+    }
+
   apr_err = apr_gethostname(hostname_str, sizeof(hostname_str), pool);
   if (apr_err)
     return svn_error_wrap_apr(apr_err, _("Can't get local hostname"));
@@ -80,10 +108,15 @@ get_lock(svn_ra_session_t *session, apr_
   mylocktoken = svn_string_createf(pool, "%s:%s", hostname_str,
                                    svn_uuid_generate(pool));
 
+  /* If we succeed, this is what the property will be set to. */
+  *lock_string_p = mylocktoken;
+
   subpool = svn_pool_create(pool);
 
   for (i = 0; i < LOCK_RETRIES; ++i)
     {
+      svn_error_t *err;
+
       svn_pool_clear(subpool);
 
       SVN_ERR(svn_ra_rev_prop(session, 0, SVNRDUMP_PROP_LOCK, &reposlocktoken,
@@ -106,9 +139,27 @@ get_lock(svn_ra_session_t *session, apr_
         }
       else if (i < LOCK_RETRIES - 1)
         {
+          const svn_string_t *unset = NULL;
+
           /* Except in the very last iteration, try to set the lock. */
-          SVN_ERR(svn_ra_change_rev_prop(session, 0, SVNRDUMP_PROP_LOCK,
-                                         mylocktoken, subpool));
+          err = svn_ra_change_rev_prop2(session, 0, SVNRDUMP_PROP_LOCK,
+                                        be_atomic ? &unset : NULL,
+                                        mylocktoken, subpool);
+
+          if (be_atomic && err && is_atomicity_error(err))
+            /* Someone else has the lock.  Let's loop. */
+            svn_error_clear(err);
+          else if (be_atomic && err == SVN_NO_ERROR)
+            /* We have the lock. 
+
+               However, for compatibility with concurrent svnsync's that don't
+               support atomicity, loop anyway to double-check that they haven't
+               overwritten our lock.
+             */
+            continue;
+          else
+            /* Genuine error, or we aren't atomic and need to loop. */
+            SVN_ERR(err);
         }
     }
 
@@ -182,6 +233,7 @@ new_node_record(void **node_baton,
   void *commit_edit_baton;
   char *ancestor_path;
   apr_array_header_t *residual_open_path;
+  char *relpath_compose;
   const char *nb_dirname;
   apr_size_t residual_close_count;
   int i;
@@ -304,8 +356,11 @@ new_node_record(void **node_baton,
         
       for (i = 0; i < residual_open_path->nelts; i ++)
         {
-          SVN_ERR(commit_editor->open_directory(APR_ARRAY_IDX(residual_open_path,
-                                                              i, const char *),
+          relpath_compose =
+            svn_relpath_join(rb->db->relpath,
+                             APR_ARRAY_IDX(residual_open_path, i, const char *),
+                             rb->pool);
+          SVN_ERR(commit_editor->open_directory(relpath_compose,
                                                 rb->db->baton,
                                                 rb->rev - 1,
                                                 rb->pool, &child_baton));
@@ -313,10 +368,7 @@ new_node_record(void **node_baton,
           child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
           child_db->baton = child_baton;
           child_db->depth = rb->db->depth + 1;
-          child_db->relpath = svn_relpath_join(rb->db->relpath,
-                                               APR_ARRAY_IDX(residual_open_path,
-                                                             i, const char *),
-                                               rb->pool);
+          child_db->relpath = relpath_compose;
           child_db->parent = rb->db;
           rb->db = child_db;
         }
@@ -394,8 +446,8 @@ set_revision_property(void *baton,
   else
     /* Special handling for revision 0; this is safe because the
        commit_editor hasn't been created yet. */
-    SVN_ERR(svn_ra_change_rev_prop(rb->pb->session, rb->rev, name, value,
-                                   rb->pool));
+    SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, rb->rev,
+                                    name, NULL, value, rb->pool));
 
   /* Remember any datestamp/ author that passes through (see comment
      in close_revision). */
@@ -419,14 +471,21 @@ set_node_property(void *baton,
   commit_editor = nb->rb->pb->commit_editor;
   pool = nb->rb->pool;
 
-  LDR_DBG(("Applying properties on %p\n", nb->file_baton));
-  if (nb->kind == svn_node_file)
-    SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
-                                            value, pool));
-  else
-    SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
-                                           value, pool));
-
+  switch (nb->kind)
+    {
+    case svn_node_file:
+      LDR_DBG(("Applying properties on %p\n", nb->file_baton));
+      SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
+                                              value, pool));
+      break;
+    case svn_node_dir:
+      LDR_DBG(("Applying properties on %p\n", nb->rb->db->baton));
+      SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
+                                             value, pool));
+      break;
+    default:
+      break;
+    }
   return SVN_NO_ERROR;
 }
 
@@ -552,12 +611,12 @@ close_revision(void *baton)
 
   /* svn_fs_commit_txn rewrites the datestamp/ author property-
      rewrite it by hand after closing the commit_editor. */
-  SVN_ERR(svn_ra_change_rev_prop(rb->pb->session, rb->rev,
-                                 SVN_PROP_REVISION_DATE,
-                                 rb->datestamp, rb->pool));
-  SVN_ERR(svn_ra_change_rev_prop(rb->pb->session, rb->rev,
-                                 SVN_PROP_REVISION_AUTHOR,
-                                 rb->author, rb->pool));
+  SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, rb->rev,
+                                  SVN_PROP_REVISION_DATE,
+                                  NULL, rb->datestamp, rb->pool));
+  SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, rb->rev,
+                                  SVN_PROP_REVISION_AUTHOR,
+                                  NULL, rb->author, rb->pool));
 
   svn_pool_destroy(rb->pool);
 
@@ -602,14 +661,25 @@ drive_dumpstream_loader(svn_stream_t *st
                         svn_ra_session_t *session,
                         apr_pool_t *pool)
 {
-  struct parse_baton *pb;
-  pb = parse_baton;
+  struct parse_baton *pb = parse_baton;
+  const svn_string_t *lock_string;
+  svn_boolean_t be_atomic;
+  svn_error_t *err;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
 
-  SVN_ERR(get_lock(session, pool));
+  SVN_ERR(get_lock(&lock_string, session, pool));
   SVN_ERR(svn_ra_get_repos_root2(session, &(pb->root_url), pool));
   SVN_ERR(svn_repos_parse_dumpstream2(stream, parser, parse_baton,
                                       NULL, NULL, pool));
-  SVN_ERR(svn_ra_change_rev_prop(session, 0, SVNRDUMP_PROP_LOCK, NULL, pool));
+  err = svn_ra_change_rev_prop2(session, 0, SVNRDUMP_PROP_LOCK,
+                                 be_atomic ? &lock_string : NULL, NULL, pool);
+  if (is_atomicity_error(err))
+    return svn_error_quick_wrap(err,
+                                _("\"svnrdump load\"'s lock was stolen; "
+                                  "can't remove it"));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/performance/subversion/svnrdump/load_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnrdump/load_editor.h?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnrdump/load_editor.h (original)
+++ subversion/branches/performance/subversion/svnrdump/load_editor.h Sun Sep 26 11:58:58 2010
@@ -89,11 +89,10 @@ struct revision_baton
 };
 
 /**
- * Build up a load editor @a parser for parsing a dumpfile stream from @a stream
- * set to fire the appropriate callbacks in load editor along with a
- * @a parser_baton, using @a pool for all memory allocations. The
- * @a editor/ @a edit_baton are central to the functionality of the
- *  parser.
+ * Build up a dumpstream parser @a parser (and corresponding baton @a
+ * parse_baton) to fire the appropriate callbacks in a commit editor
+ * set to commit to session @a session. Use @a pool for all memory
+ * allocations.
  */
 svn_error_t *
 get_dumpstream_loader(const svn_repos_parse_fns2_t **parser,
@@ -102,8 +101,10 @@ get_dumpstream_loader(const svn_repos_pa
                       apr_pool_t *pool);
 
 /**
- * Drive the load editor @a editor using the data in @a stream using
- * @a pool for all memory allocations.
+ * Drive the dumpstream loader described by @a parser and @a
+ * parse_baton to parse and commit the stream @a stream to the
+ * location described by @a session. Use @a pool for all memory
+ * allocations.
  */
 svn_error_t *
 drive_dumpstream_loader(svn_stream_t *stream,

Modified: subversion/branches/performance/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnrdump/svnrdump.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/performance/subversion/svnrdump/svnrdump.c Sun Sep 26 11:58:58 2010
@@ -110,7 +110,7 @@ struct replay_baton {
   svn_boolean_t quiet;
 };
 
-typedef struct {
+typedef struct opt_baton_t {
   svn_ra_session_t *session;
   const char *url;
   svn_revnum_t start_revision;
@@ -137,6 +137,7 @@ replay_revstart(svn_revnum_t revision,
   SVN_ERR(svn_stream_printf(stdout_stream, pool,
                             SVN_REPOS_DUMPFILE_REVISION_NUMBER
                             ": %ld\n", revision));
+  SVN_ERR(normalize_props(rev_props, pool));
   propstring = svn_stringbuf_create_ensure(0, pool);
   revprop_stream = svn_stream_from_stringbuf(propstring, pool);
   SVN_ERR(svn_hash_write2(rev_props, revprop_stream, "PROPS-END", pool));

Modified: subversion/branches/performance/subversion/svnserve/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnserve/cyrus_auth.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnserve/cyrus_auth.c (original)
+++ subversion/branches/performance/subversion/svnserve/cyrus_auth.c Sun Sep 26 11:58:58 2010
@@ -361,7 +361,7 @@ svn_error_t *cyrus_auth_request(svn_ra_s
 
       if ((p = strchr(user, '@')) != NULL)
         /* Drop the realm part. */
-        b->user = apr_pstrndup(b->pool, user, p - (char *)user);
+        b->user = apr_pstrndup(b->pool, user, p - (const char *)user);
       else
         {
           svn_error_t *err;

Modified: subversion/branches/performance/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnserve/serve.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnserve/serve.c (original)
+++ subversion/branches/performance/subversion/svnserve/serve.c Sun Sep 26 11:58:58 2010
@@ -994,6 +994,65 @@ static svn_error_t *get_dated_rev(svn_ra
   return SVN_NO_ERROR;
 }
 
+/* Common logic for change_rev_prop() and change_rev_prop2(). */
+static svn_error_t *do_change_rev_prop(svn_ra_svn_conn_t *conn,
+                                       server_baton_t *b,
+                                       svn_revnum_t rev,
+                                       const char *name,
+                                       const svn_string_t *const *old_value_p,
+                                       const svn_string_t *value,
+                                       apr_pool_t *pool)
+{
+  SVN_ERR(must_have_access(conn, pool, b, svn_authz_write, NULL, FALSE));
+  SVN_ERR(log_command(b, conn, pool, "%s",
+                      svn_log__change_rev_prop(rev, name, pool)));
+  SVN_CMD_ERR(svn_repos_fs_change_rev_prop4(b->repos, rev, b->user,
+                                            name, old_value_p, value,
+                                            TRUE, TRUE,
+                                            authz_check_access_cb_func(b), b,
+                                            pool));
+  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *change_rev_prop2(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                                     apr_array_header_t *params, void *baton)
+{
+  server_baton_t *b = baton;
+  svn_revnum_t rev;
+  const char *name;
+  svn_string_t *value;
+  const svn_string_t *const *old_value_p;
+  svn_string_t *old_value;
+  svn_boolean_t dont_care;
+
+  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "rc(?s)(b?s)",
+                                 &rev, &name, &value,
+                                 &dont_care, &old_value));
+
+  /* Argument parsing. */
+  if (dont_care)
+    old_value_p = NULL;
+  else
+    old_value_p = (const svn_string_t *const *)&old_value;
+
+  /* Input validation. */
+  if (dont_care && old_value)
+    {
+      svn_error_t *err;
+      err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             "'previous-value' and 'dont-care' cannot both be "
+                             "set in 'change-rev-prop2' request");
+      return log_fail_and_flush(err, b, conn, pool);
+    }
+
+  /* Do it. */
+  SVN_ERR(do_change_rev_prop(conn, b, rev, name, old_value_p, value, pool));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *change_rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                     apr_array_header_t *params, void *baton)
 {
@@ -1006,14 +1065,8 @@ static svn_error_t *change_rev_prop(svn_
      optional element pattern "(?s)" isn't used. */
   SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "rc?s", &rev, &name, &value));
 
-  SVN_ERR(must_have_access(conn, pool, b, svn_authz_write, NULL, FALSE));
-  SVN_ERR(log_command(b, conn, pool, "%s",
-                      svn_log__change_rev_prop(rev, name, pool)));
-  SVN_CMD_ERR(svn_repos_fs_change_rev_prop3(b->repos, rev, b->user,
-                                            name, value, TRUE, TRUE,
-                                            authz_check_access_cb_func(b), b,
-                                            pool));
-  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
+  SVN_ERR(do_change_rev_prop(conn, b, rev, name, NULL, value, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -2768,6 +2821,7 @@ static const svn_ra_svn_cmd_entry_t main
   { "get-latest-rev",  get_latest_rev },
   { "get-dated-rev",   get_dated_rev },
   { "change-rev-prop", change_rev_prop },
+  { "change-rev-prop2",change_rev_prop2 },
   { "rev-proplist",    rev_proplist },
   { "rev-prop",        rev_prop },
   { "commit",          commit },
@@ -2992,7 +3046,7 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
   /* Send greeting.  We don't support version 1 any more, so we can
    * send an empty mechlist. */
   if (params->compression_level > 0)
-    SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "nn()(wwwwwww)",
+    SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "nn()(wwwwwwww)",
                                           (apr_uint64_t) 2, (apr_uint64_t) 2,
                                           SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                           SVN_RA_SVN_CAP_SVNDIFF1,
@@ -3000,15 +3054,17 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
                                           SVN_RA_SVN_CAP_COMMIT_REVPROPS,
                                           SVN_RA_SVN_CAP_DEPTH,
                                           SVN_RA_SVN_CAP_LOG_REVPROPS,
+                                          SVN_RA_SVN_CAP_ATOMIC_REVPROPS,
                                           SVN_RA_SVN_CAP_PARTIAL_REPLAY));
   else
-    SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "nn()(wwwwww)",
+    SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "nn()(wwwwwww)",
                                           (apr_uint64_t) 2, (apr_uint64_t) 2,
                                           SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                           SVN_RA_SVN_CAP_ABSENT_ENTRIES,
                                           SVN_RA_SVN_CAP_COMMIT_REVPROPS,
                                           SVN_RA_SVN_CAP_DEPTH,
                                           SVN_RA_SVN_CAP_LOG_REVPROPS,
+                                          SVN_RA_SVN_CAP_ATOMIC_REVPROPS,
                                           SVN_RA_SVN_CAP_PARTIAL_REPLAY));
 
   /* Read client response, which we assume to be in version 2 format:

Modified: subversion/branches/performance/subversion/svnsync/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svnsync/main.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svnsync/main.c (original)
+++ subversion/branches/performance/subversion/svnsync/main.c Sun Sep 26 11:58:58 2010
@@ -284,6 +284,37 @@ check_lib_versions(void)
 }
 
 
+/* Does ERR mean "the current value of the revprop isn't equal to
+   the *OLD_VALUE_P you gave me"?
+ */
+static svn_boolean_t is_atomicity_error(svn_error_t *err)
+{
+  return svn_error_has_cause(err, SVN_ERR_FS_PROP_BASEVALUE_MISMATCH);
+}
+
+/* Remove the lock on SESSION iff the lock is owned by MYLOCKTOKEN. */
+static svn_error_t *
+maybe_unlock(svn_ra_session_t *session,
+             const svn_string_t *mylocktoken,
+             apr_pool_t *scratch_pool)
+{
+  svn_string_t *reposlocktoken;
+  svn_boolean_t be_atomic;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                scratch_pool));
+
+  SVN_ERR(svn_ra_rev_prop(session, 0, SVNSYNC_PROP_LOCK, &reposlocktoken,
+                          scratch_pool));
+  if (reposlocktoken && strcmp(reposlocktoken->data, mylocktoken->data) == 0)
+    SVN_ERR(svn_ra_change_rev_prop2(session, 0, SVNSYNC_PROP_LOCK, 
+                                    be_atomic ? &mylocktoken : NULL, NULL,
+                                    scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Acquire a lock (of sorts) on the repository associated with the
  * given RA SESSION. This lock is just a revprop change attempt in a
  * time-delay loop. This function is duplicated by svnrdump in
@@ -294,14 +325,36 @@ check_lib_versions(void)
  * applications to avoid duplication.
  */
 static svn_error_t *
-get_lock(svn_ra_session_t *session, apr_pool_t *pool)
+get_lock(const svn_string_t **lock_string_p,
+         svn_ra_session_t *session,
+         apr_pool_t *pool)
 {
   char hostname_str[APRMAXHOSTLEN + 1] = { 0 };
   svn_string_t *mylocktoken, *reposlocktoken;
   apr_status_t apr_err;
+  svn_boolean_t be_atomic;
   apr_pool_t *subpool;
   int i;
 
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
+  if (! be_atomic)
+    {
+      /* Pre-1.7 server.  Can't lock without a race condition.
+         See issue #3546.
+       */
+      svn_error_t *err;
+
+      err = svn_error_create(
+              SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+              _("Target server does not support atomic revision property "
+                "edits; consider upgrading it to 1.7 or using an external "
+                "locking program"));
+      svn_handle_warning2(stderr, err, "svnsync: ");
+      svn_error_clear(err);
+    }
+
   apr_err = apr_gethostname(hostname_str, sizeof(hostname_str), pool);
   if (apr_err)
     return svn_error_wrap_apr(apr_err, _("Can't get local hostname"));
@@ -309,17 +362,29 @@ get_lock(svn_ra_session_t *session, apr_
   mylocktoken = svn_string_createf(pool, "%s:%s", hostname_str,
                                    svn_uuid_generate(pool));
 
+  /* If we succeed, this is what the property will be set to. */
+  *lock_string_p = mylocktoken;
+
   subpool = svn_pool_create(pool);
 
 #define SVNSYNC_LOCK_RETRIES 10
   for (i = 0; i < SVNSYNC_LOCK_RETRIES; ++i)
     {
+      svn_error_t *err;
+
       svn_pool_clear(subpool);
-      SVN_ERR(check_cancel(NULL));
+
+      /* If we're cancelled, don't leave a stray lock behind. */
+      err = check_cancel(NULL);
+      if (err && err->apr_err == SVN_ERR_CANCELLED)
+      	return svn_error_compose_create(
+      	             maybe_unlock(session, mylocktoken, subpool),
+      	             err);
+      else
+      	SVN_ERR(err);
 
       SVN_ERR(svn_ra_rev_prop(session, 0, SVNSYNC_PROP_LOCK, &reposlocktoken,
                               subpool));
-
       if (reposlocktoken)
         {
           /* Did we get it?   If so, we're done, otherwise we sleep. */
@@ -337,9 +402,27 @@ get_lock(svn_ra_session_t *session, apr_
         }
       else if (i < SVNSYNC_LOCK_RETRIES - 1)
         {
+          const svn_string_t *unset = NULL;
+
           /* Except in the very last iteration, try to set the lock. */
-          SVN_ERR(svn_ra_change_rev_prop(session, 0, SVNSYNC_PROP_LOCK,
-                                         mylocktoken, subpool));
+          err = svn_ra_change_rev_prop2(session, 0, SVNSYNC_PROP_LOCK,
+                                        be_atomic ? &unset : NULL,
+                                        mylocktoken, subpool);
+
+          if (be_atomic && err && is_atomicity_error(err))
+            /* Someone else has the lock.  Let's loop. */
+            svn_error_clear(err);
+          else if (be_atomic && err == SVN_NO_ERROR)
+            /* We have the lock. 
+
+               However, for compatibility with concurrent svnsync's that don't
+               support atomicity, loop anyway to double-check that they haven't
+               overwritten our lock.
+             */
+            continue;
+          else
+            /* Genuine error, or we aren't atomic and need to loop. */
+            SVN_ERR(err);
         }
     }
 
@@ -387,12 +470,24 @@ with_locked(svn_ra_session_t *session,
             apr_pool_t *pool)
 {
   svn_error_t *err, *err2;
+  const svn_string_t *lock_string;
+  svn_boolean_t be_atomic;
 
-  SVN_ERR(get_lock(session, pool));
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
+
+  SVN_ERR(get_lock(&lock_string, session, pool));
 
   err = func(session, baton, pool);
 
-  err2 = svn_ra_change_rev_prop(session, 0, SVNSYNC_PROP_LOCK, NULL, pool);
+  err2 = svn_ra_change_rev_prop2(session, 0, SVNSYNC_PROP_LOCK,
+                                 be_atomic ? &lock_string : NULL, NULL, pool);
+  if (is_atomicity_error(err2))
+    err2 = svn_error_quick_wrap(err2,
+                                _("svnsync's lock was stolen; "
+                                  "can't remove it"));
+
 
   return svn_error_compose_create(err, svn_error_return(err2));
 }
@@ -457,8 +552,8 @@ remove_props_not_in_source(svn_ra_sessio
 
       /* Delete property if the name can't be found in SOURCE_PROPS. */
       if (! apr_hash_get(source_props, propname, APR_HASH_KEY_STRING))
-        SVN_ERR(svn_ra_change_rev_prop(session, rev, propname, NULL,
-                                       subpool));
+        SVN_ERR(svn_ra_change_rev_prop2(session, rev, propname, NULL,
+                                        NULL, subpool));
     }
 
   svn_pool_destroy(subpool);
@@ -541,8 +636,8 @@ write_revprops(int *filtered_count,
       if (strncmp(propname, SVNSYNC_PROP_PREFIX,
                   sizeof(SVNSYNC_PROP_PREFIX) - 1) != 0)
         {
-          SVN_ERR(svn_ra_change_rev_prop(session, rev, propname, propval,
-                                         subpool));
+          SVN_ERR(svn_ra_change_rev_prop2(session, rev, propname, NULL,
+                                          propval, subpool));
         }
       else
         {
@@ -676,6 +771,11 @@ make_subcommand_baton(opt_baton_t *opt_b
   return b;
 }
 
+static svn_error_t *
+open_target_session(svn_ra_session_t **to_session_p,
+                    subcommand_baton_t *baton,
+                    apr_pool_t *pool);
+
 
 /*** `svnsync init' ***/
 
@@ -749,17 +849,17 @@ do_initialize(svn_ra_session_t *to_sessi
              "repository"));
     }
 
-  SVN_ERR(svn_ra_change_rev_prop(to_session, 0, SVNSYNC_PROP_FROM_URL,
-                                 svn_string_create(baton->from_url, pool),
-                                 pool));
+  SVN_ERR(svn_ra_change_rev_prop2(to_session, 0, SVNSYNC_PROP_FROM_URL, NULL,
+                                  svn_string_create(baton->from_url, pool),
+                                  pool));
 
   SVN_ERR(svn_ra_get_uuid2(from_session, &uuid, pool));
-  SVN_ERR(svn_ra_change_rev_prop(to_session, 0, SVNSYNC_PROP_FROM_UUID,
-                                 svn_string_create(uuid, pool), pool));
+  SVN_ERR(svn_ra_change_rev_prop2(to_session, 0, SVNSYNC_PROP_FROM_UUID, NULL,
+                                  svn_string_create(uuid, pool), pool));
 
-  SVN_ERR(svn_ra_change_rev_prop(to_session, 0, SVNSYNC_PROP_LAST_MERGED_REV,
-                                 svn_string_createf(pool, "%ld", latest),
-                                 pool));
+  SVN_ERR(svn_ra_change_rev_prop2(to_session, 0, SVNSYNC_PROP_LAST_MERGED_REV,
+                                  NULL, svn_string_createf(pool, "%ld", latest),
+                                  pool));
 
   /* Copy all non-svnsync revprops from the LATEST rev in the source
      repository into the destination, notifying about normalized
@@ -815,9 +915,7 @@ initialize_cmd(apr_getopt_t *os, void *b
                              _("Path '%s' is not a URL"), from_url);
 
   baton = make_subcommand_baton(opt_baton, to_url, from_url, 0, 0, pool);
-  SVN_ERR(svn_ra_open4(&to_session, NULL, baton->to_url, NULL,
-                       &(baton->sync_callbacks), baton, baton->config, pool));
-  SVN_ERR(check_if_session_is_at_repos_root(to_session, baton->to_url, pool));
+  SVN_ERR(open_target_session(&to_session, baton, pool));
   if (opt_baton->disable_locking)
     SVN_ERR(do_initialize(to_session, baton, pool));
   else
@@ -897,6 +995,23 @@ open_source_session(svn_ra_session_t **f
   return SVN_NO_ERROR;
 }
 
+/* Set *TARGET_SESSION_P to an RA session associated with the target
+ * repository of the synchronization.
+ */
+static svn_error_t *
+open_target_session(svn_ra_session_t **target_session_p,
+                    subcommand_baton_t *baton,
+                    apr_pool_t *pool)
+{
+  svn_ra_session_t *target_session;
+  SVN_ERR(svn_ra_open4(&target_session, NULL, baton->to_url, NULL,
+                       &(baton->sync_callbacks), baton, baton->config, pool));
+  SVN_ERR(check_if_session_is_at_repos_root(target_session, baton->to_url, pool));
+
+  *target_session_p = target_session;
+  return SVN_NO_ERROR;
+}
+
 /* Replay baton, used during sychnronization. */
 typedef struct {
   svn_ra_session_t *from_session;
@@ -1003,11 +1118,11 @@ replay_rev_started(svn_revnum_t revision
      NOTE: We have to set this before we start the commit editor,
      because ra_svn doesn't let you change rev props during a
      commit. */
-  SVN_ERR(svn_ra_change_rev_prop(rb->to_session, 0,
-                                 SVNSYNC_PROP_CURRENTLY_COPYING,
-                                 svn_string_createf(pool, "%ld",
-                                                    revision),
-                                 pool));
+  SVN_ERR(svn_ra_change_rev_prop2(rb->to_session, 0,
+                                  SVNSYNC_PROP_CURRENTLY_COPYING,
+                                  NULL,
+                                  svn_string_createf(pool, "%ld", revision),
+                                  pool));
 
   /* The actual copy is just a replay hooked up to a commit.  Include
      all the revision properties from the source repositories, except
@@ -1116,19 +1231,20 @@ replay_rev_finished(svn_revnum_t revisio
   svn_pool_clear(subpool);
 
   /* Ok, we're done, bring the last-merged-rev property up to date. */
-  SVN_ERR(svn_ra_change_rev_prop
-          (rb->to_session,
+  SVN_ERR(svn_ra_change_rev_prop2(
+           rb->to_session,
            0,
            SVNSYNC_PROP_LAST_MERGED_REV,
+           NULL,
            svn_string_create(apr_psprintf(pool, "%ld", revision),
                              subpool),
            subpool));
 
   /* And finally drop the currently copying prop, since we're done
      with this revision. */
-  SVN_ERR(svn_ra_change_rev_prop(rb->to_session, 0,
-                                 SVNSYNC_PROP_CURRENTLY_COPYING,
-                                 NULL, subpool));
+  SVN_ERR(svn_ra_change_rev_prop2(rb->to_session, 0,
+                                  SVNSYNC_PROP_CURRENTLY_COPYING,
+                                  NULL, NULL, subpool));
 
   /* Notify the user that we copied revision properties. */
   if (! rb->sb->quiet)
@@ -1221,12 +1337,12 @@ do_synchronize(svn_ra_session_t *to_sess
              end up not being able to tell if there have been bogus
              (i.e. non-svnsync) commits to the dest repository. */
 
-          SVN_ERR(svn_ra_change_rev_prop(to_session, 0,
-                                         SVNSYNC_PROP_LAST_MERGED_REV,
-                                         last_merged_rev, pool));
-          SVN_ERR(svn_ra_change_rev_prop(to_session, 0,
-                                         SVNSYNC_PROP_CURRENTLY_COPYING,
-                                         NULL, pool));
+          SVN_ERR(svn_ra_change_rev_prop2(to_session, 0,
+                                          SVNSYNC_PROP_LAST_MERGED_REV,
+                                          NULL, last_merged_rev, pool));
+          SVN_ERR(svn_ra_change_rev_prop2(to_session, 0,
+                                          SVNSYNC_PROP_CURRENTLY_COPYING,
+                                          NULL, NULL, pool));
         }
       /* If copying > to_latest, then we just fall through to
          attempting to copy the revision again. */
@@ -1315,9 +1431,7 @@ synchronize_cmd(apr_getopt_t *os, void *
     }
 
   baton = make_subcommand_baton(opt_baton, to_url, from_url, 0, 0, pool);
-  SVN_ERR(svn_ra_open4(&to_session, NULL, baton->to_url, NULL,
-                       &(baton->sync_callbacks), baton, baton->config, pool));
-  SVN_ERR(check_if_session_is_at_repos_root(to_session, baton->to_url, pool));
+  SVN_ERR(open_target_session(&to_session, baton, pool));
   if (opt_baton->disable_locking)
     SVN_ERR(do_synchronize(to_session, baton, pool));
   else
@@ -1551,9 +1665,7 @@ copy_revprops_cmd(apr_getopt_t *os, void
       
   baton = make_subcommand_baton(opt_baton, to_url, from_url,
                                 start_rev, end_rev, pool);
-  SVN_ERR(svn_ra_open4(&to_session, NULL, baton->to_url, NULL,
-                       &(baton->sync_callbacks), baton, baton->config, pool));
-  SVN_ERR(check_if_session_is_at_repos_root(to_session, baton->to_url, pool));
+  SVN_ERR(open_target_session(&to_session, baton, pool));
   if (opt_baton->disable_locking)
     SVN_ERR(do_copy_revprops(to_session, baton, pool));
   else
@@ -1595,9 +1707,7 @@ info_cmd(apr_getopt_t *os, void *b, apr_
 
   /* Open an RA session to the mirror repository URL. */
   baton = make_subcommand_baton(opt_baton, to_url, NULL, 0, 0, pool);
-  SVN_ERR(svn_ra_open4(&to_session, NULL, baton->to_url, NULL,
-                       &(baton->sync_callbacks), baton, baton->config, pool));
-  SVN_ERR(check_if_session_is_at_repos_root(to_session, baton->to_url, pool));
+  SVN_ERR(open_target_session(&to_session, baton, pool));
 
   /* Verify that the repos has been initialized for synchronization. */
   SVN_ERR(svn_ra_rev_prop(to_session, 0, SVNSYNC_PROP_FROM_URL,

Propchange: subversion/branches/performance/subversion/tests/cmdline/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Sep 26 11:58:58 2010
@@ -6,4 +6,5 @@ httpd-*
 *~
 .*~
 entries-dump
+atomic-ra-revprop-change
 .libs

Modified: subversion/branches/performance/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/prop_tests.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/prop_tests.py Sun Sep 26 11:58:58 2010
@@ -1973,6 +1973,82 @@ def obstructed_subdirs(sbox):
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 
+def atomic_over_ra(sbox):
+  "test revprop atomicity guarantees of libsvn_ra"
+
+  sbox.build(create_wc=False)
+  repo_url = sbox.repo_url
+
+  # From this point on, similar to ../libsvn_fs-fs-test.c:revision_props().
+  s1 = "violet"
+  s2 = "wrong value"
+
+  # But test "" explicitly, since the RA layers have to marshal "" and <unset>
+  # differently.
+  s3 = ""
+
+  # Initial state.
+  svntest.actions.enable_revprop_changes(sbox.repo_dir)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'propset', '--revprop', '-r', '0',
+                                     'flower', s1, repo_url)
+
+  # Helpers.
+  
+  def expect_old_server_fail(old_value, proposed_value):
+    # We are setting a (possibly "not present") expectation for the old value,
+    # so we should fail.
+    expected_stderr = ".*doesn't advertise.*ATOMIC_REVPROP"
+    svntest.actions.run_and_verify_atomic_ra_revprop_change(
+       None, None, expected_stderr, 1, repo_url, 0, 'flower',
+       old_value, proposed_value)
+
+    # The original value is still there.
+    svntest.actions.check_prop('flower', repo_url, [s1], 0)
+
+  def FAILS_WITH_BPV(not_the_old_value, proposed_value):
+    if svntest.main.server_has_atomic_revprop():
+      svntest.actions.run_and_verify_atomic_ra_revprop_change(
+         None, None, [], 0, repo_url, 0, 'flower',
+         not_the_old_value, proposed_value, True)
+    else:
+      expect_old_server_fail(not_the_old_value, proposed_value)
+
+  def PASSES_WITHOUT_BPV(yes_the_old_value, proposed_value):
+    if svntest.main.server_has_atomic_revprop():
+      svntest.actions.run_and_verify_atomic_ra_revprop_change(
+         None, None, [], 0, repo_url, 0, 'flower',
+         yes_the_old_value, proposed_value, False)
+    else:
+      expect_old_server_fail(yes_the_old_value, proposed_value)
+
+  # Value of "flower" is 's1'.
+  FAILS_WITH_BPV(s2, s1)
+  FAILS_WITH_BPV(s3, s1)
+  PASSES_WITHOUT_BPV(s1, s2)
+
+  # Value of "flower" is 's2'.
+  PASSES_WITHOUT_BPV(s2, s3)
+
+  # Value of "flower" is 's3'.
+  FAILS_WITH_BPV(None, s3)
+  FAILS_WITH_BPV(s1, s3)
+  PASSES_WITHOUT_BPV(s3, s2)
+
+  # Value of "flower" is 's2'.
+  FAILS_WITH_BPV(None, None)
+  FAILS_WITH_BPV(s1, None)
+  FAILS_WITH_BPV(s3, None)
+  PASSES_WITHOUT_BPV(s2, None)
+
+  # Value of "flower" is <not set>.
+  FAILS_WITH_BPV(s2, s1)
+  FAILS_WITH_BPV(s3, s1)
+  PASSES_WITHOUT_BPV(None, s1)
+
+  # Value of "flower" is 's1'.
+  svntest.actions.check_prop('flower', repo_url, [s1], 0)
+
 ########################################################################
 # Run the tests
 
@@ -2016,6 +2092,7 @@ test_list = [ None,
               rm_of_replaced_file,
               prop_reject_grind,
               obstructed_subdirs,
+              atomic_over_ra,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/svnrdump_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/svnrdump_tests.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/svnrdump_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/svnrdump_tests.py Sun Sep 26 11:58:58 2010
@@ -65,9 +65,12 @@ def build_repos(sbox):
   # Create an empty repository.
   svntest.main.create_repos(sbox.repo_dir)
 
-def run_dump_test(sbox, dumpfile_name):
+def run_dump_test(sbox, dumpfile_name, expected_dumpfile_name = None,
+                  subdir = None):
   """Load a dumpfile using 'svnadmin load', dump it with 'svnrdump
-  dump' and check that the same dumpfile is produced"""
+  dump' and check that the same dumpfile is produced or that
+  expected_dumpfile_name is produced if provided. Additionally, the
+  subdir argument appends itself to the URL"""
 
   # Create an empty sanbox repository
   build_repos(sbox)
@@ -83,19 +86,28 @@ def run_dump_test(sbox, dumpfile_name):
                            'rb').readlines()
 
   svntest.actions.run_and_verify_load(sbox.repo_dir, svnadmin_dumpfile)
+  
+  repo_url = sbox.repo_url
+  if subdir:
+    repo_url = repo_url + subdir
 
   # Create a dump file using svnrdump
   svnrdump_dumpfile = \
       svntest.actions.run_and_verify_svnrdump(None, svntest.verify.AnyOutput,
                                               [], 0, '-q', 'dump',
-                                              sbox.repo_url)
+                                              repo_url)
+
+  if expected_dumpfile_name:
+    svnadmin_dumpfile = open(os.path.join(svnrdump_tests_dir,
+                                          expected_dumpfile_name),
+                             'rb').readlines()
 
   # Compare the output from stdout
   svntest.verify.compare_and_display_lines(
     "Dump files", "DUMP", svnadmin_dumpfile, svnrdump_dumpfile,
     None, mismatched_headers_re)
 
-def run_load_test(sbox, dumpfile_name):
+def run_load_test(sbox, dumpfile_name, expected_dumpfile_name = None):
   """Load a dumpfile using 'svnrdump load', dump it with 'svnadmin
   dump' and check that the same dumpfile is produced"""
 
@@ -130,6 +142,11 @@ def run_load_test(sbox, dumpfile_name):
   # Create a dump file using svnadmin dump
   svnadmin_dumpfile = svntest.actions.run_and_verify_dump(sbox.repo_dir, True)
 
+  if expected_dumpfile_name:
+    svnrdump_dumpfile = open(os.path.join(svnrdump_tests_dir,
+                                          expected_dumpfile_name),
+                             'rb').readlines()
+
   # Compare the output from stdout
   svntest.verify.compare_and_display_lines(
     "Dump files", "DUMP", svnrdump_dumpfile, svnadmin_dumpfile)
@@ -167,6 +184,10 @@ def revision_0_load(sbox):
 #     docs/         (Added r6)
 #       README      (Added r6)
 
+def skeleton_dump(sbox):
+  "dump: skeleton repository"
+  run_dump_test(sbox, "skeleton.dump")
+
 def skeleton_load(sbox):
   "load: skeleton repository"
   run_load_test(sbox, "skeleton.dump")
@@ -219,6 +240,22 @@ def tag_empty_trunk_load(sbox):
   "load: tag empty trunk"
   run_load_test(sbox, "tag-empty-trunk.dump")
 
+def tag_trunk_with_file_dump(sbox):
+  "dump: tag trunk containing a file"
+  run_dump_test(sbox, "tag-trunk-with-file.dump")
+
+def tag_trunk_with_file_load(sbox):
+  "load: tag trunk containing a file"
+  run_load_test(sbox, "tag-trunk-with-file.dump")
+
+def tag_trunk_with_file2_dump(sbox):
+  "dump: tag trunk containing a file (#2)"
+  run_dump_test(sbox, "tag-trunk-with-file2.dump")
+
+def tag_trunk_with_file2_load(sbox):
+  "load: tag trunk containing a file (#2)"
+  run_load_test(sbox, "tag-trunk-with-file2.dump")
+
 def dir_prop_change_dump(sbox):
   "dump: directory property changes"
   run_dump_test(sbox, "dir-prop-change.dump")
@@ -243,6 +280,16 @@ def copy_revprops_load(sbox):
   "load: copy revprops other than svn:*"
   run_load_test(sbox, "revprops.dump")
 
+def only_trunk_dump(sbox):
+  "dump: subdirectory"
+  run_dump_test(sbox, "trunk-only.dump", subdir="/trunk",
+                expected_dumpfile_name="trunk-only.expected.dump")
+
+def only_trunk_A_with_changes_dump(sbox):
+  "dump: subdirectory with changes on root"
+  run_dump_test(sbox, "trunk-A-changes.dump", subdir="/trunk/A",
+           expected_dumpfile_name="trunk-A-changes.expected.dump")
+
 def url_encoding_dump(sbox):
   "dump: url encoding issues"
   run_dump_test(sbox, "url-encoding-bug.dump")
@@ -251,6 +298,24 @@ def url_encoding_load(sbox):
   "load: url encoding issues"
   run_load_test(sbox, "url-encoding-bug.dump")
 
+def copy_bad_line_endings_dump(sbox):
+  "dump: inconsistent line endings in svn:props"
+  run_dump_test(sbox, "copy-bad-line-endings.dump",
+           expected_dumpfile_name="copy-bad-line-endings.expected.dump")
+
+def commit_a_copy_of_root_dump(sbox):
+  "dump: commit a copy of root"
+  run_dump_test(sbox, "repo-with-copy-of-root-dir.dump")
+
+def commit_a_copy_of_root_load(sbox):
+  "load: commit a copy of root"
+  run_load_test(sbox, "repo-with-copy-of-root-dir.dump")
+
+def descend_into_replace_dump(sbox):
+  "dump: descending into replaced dir looks in src"
+  run_dump_test(sbox, "descend-into-replace.dump", subdir='/trunk/H',
+                expected_dumpfile_name = "descend-into-replace.expected.dump")
+
 ########################################################################
 # Run the tests
 
@@ -260,6 +325,7 @@ test_list = [ None,
               basic_dump,
               revision_0_dump,
               revision_0_load,
+              skeleton_dump,
               skeleton_load,
               copy_and_modify_dump,
               copy_and_modify_load,
@@ -269,18 +335,28 @@ test_list = [ None,
               modified_in_place_load,
               tag_empty_trunk_dump,
               tag_empty_trunk_load,
+              tag_trunk_with_file_dump,
+              tag_trunk_with_file_load,
+              tag_trunk_with_file2_dump,
+              tag_trunk_with_file2_load,
               dir_prop_change_dump,
-              dir_prop_change_load,
+              Wimp("TODO", dir_prop_change_load, svntest.main.is_ra_type_dav),
               copy_parent_modify_prop_dump,
               copy_parent_modify_prop_load,
               url_encoding_dump,
               url_encoding_load,
               copy_revprops_dump,
-              Wimp("TODO", copy_revprops_load),
+              copy_revprops_load,
+              only_trunk_dump,
+              only_trunk_A_with_changes_dump,
               no_author_dump,
               no_author_load,
-              Wimp("TODO", move_and_modify_in_the_same_revision_dump),
-              Wimp("TODO", move_and_modify_in_the_same_revision_load),
+              move_and_modify_in_the_same_revision_dump,
+              move_and_modify_in_the_same_revision_load,
+              copy_bad_line_endings_dump,
+              commit_a_copy_of_root_dump,
+              commit_a_copy_of_root_load,
+              descend_into_replace_dump,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/svntest/actions.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/svntest/actions.py Sun Sep 26 11:58:58 2010
@@ -147,6 +147,41 @@ def guarantee_greek_repository(path):
   main.chmod_tree(path, 0666, 0666)
 
 
+def run_and_verify_atomic_ra_revprop_change(message,
+                                            expected_stdout,
+                                            expected_stderr,
+                                            expected_exit, 
+                                            url, revision, propname,
+                                            old_propval, propval,
+                                            want_error):
+  """Run atomic-ra-revprop-change helper and check its output and exit code.
+  Transforms OLD_PROPVAL and PROPVAL into a skel.
+  For HTTP, the default HTTP library is used."""
+
+  KEY_OLD_PROPVAL = "old_value_p"
+  KEY_NEW_PROPVAL = "value"
+
+  def skel_make_atom(word):
+    return "%d %s" % (len(word), word)
+
+  def make_proplist_skel_part(nick, val):
+    if val is None:
+      return ""
+    else:
+      return "%s %s" % (skel_make_atom(nick), skel_make_atom(val))
+
+  skel = "( %s %s )" % (make_proplist_skel_part(KEY_OLD_PROPVAL, old_propval),
+                        make_proplist_skel_part(KEY_NEW_PROPVAL, propval))
+
+  exit_code, out, err = main.run_atomic_ra_revprop_change(url, revision,
+                                                          propname, skel,
+                                                          want_error)
+  verify.verify_outputs("Unexpected output", out, err,
+                        expected_stdout, expected_stderr)
+  verify.verify_exit_code(message, exit_code, expected_exit)
+  return exit_code, out, err
+
+
 def run_and_verify_svnlook(message, expected_stdout,
                            expected_stderr, *varargs):
   """Like run_and_verify_svnlook2, but the expected exit code is
@@ -1735,15 +1770,22 @@ def set_prop(name, value, path, expected
   else:
     main.run_svn(expected_err, 'propset', name, value, path)
 
-def check_prop(name, path, exp_out):
-  """Verify that property NAME on PATH has a value of EXP_OUT"""
+def check_prop(name, path, exp_out, revprop=None):
+  """Verify that property NAME on PATH has a value of EXP_OUT.
+  If REVPROP is not None, then it is a revision number and
+  a revision property is sought."""
+  if revprop is not None:
+    revprop_options = ['--revprop', '-r', revprop]
+  else:
+    revprop_options = []
   # Not using run_svn because binary_mode must be set
   exit_code, out, err = main.run_command(main.svn_binary, None, 1, 'pg',
                                          '--strict', name, path,
                                          '--config-dir',
                                          main.default_config_dir,
                                          '--username', main.wc_author,
-                                         '--password', main.wc_passwd)
+                                         '--password', main.wc_passwd,
+                                         *revprop_options)
   if out != exp_out:
     print("svn pg --strict %s output does not match expected." % name)
     print("Expected standard output:  %s\n" % exp_out)

Modified: subversion/branches/performance/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/svntest/main.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/svntest/main.py Sun Sep 26 11:58:58 2010
@@ -158,6 +158,8 @@ svnversion_binary = os.path.abspath('../
 svndumpfilter_binary = os.path.abspath('../../svndumpfilter/svndumpfilter' + \
                                        _exe)
 entriesdump_binary = os.path.abspath('entries-dump' + _exe)
+atomic_ra_revprop_change_binary = os.path.abspath('atomic-ra-revprop-change' + \
+                                                  _exe)
 
 # Location to the pristine repository, will be calculated from test_area_url
 # when we know what the user specified for --url.
@@ -639,6 +641,20 @@ def run_entriesdump_subdirs(path):
                                                         0, 0, None, '--subdirs', path)
   return [line.strip() for line in stdout_lines if not line.startswith("DBG:")]
 
+def run_atomic_ra_revprop_change(url, revision, propname, skel, want_error):
+  """Run the atomic-ra-revprop-change helper, returning its exit code, stdout, 
+  and stderr.  For HTTP, default HTTP library is used."""
+  # use spawn_process rather than run_command to avoid copying all the data
+  # to stdout in verbose mode.
+  #exit_code, stdout_lines, stderr_lines = spawn_process(entriesdump_binary,
+  #                                                      0, 0, None, path)
+
+  # This passes HTTP_LIBRARY in addition to our params.
+  return run_command(atomic_ra_revprop_change_binary, True, False, 
+                     url, revision, propname, skel,
+                     options.http_library, want_error and 1 or 0)
+
+
 # Chmod recursively on a whole subtree
 def chmod_tree(path, mode, mask):
   for dirpath, dirs, files in os.walk(path):
@@ -1072,6 +1088,9 @@ def server_has_partial_replay():
 def server_enforces_date_syntax():
   return options.server_minor_version >= 5
 
+def server_has_atomic_revprop():
+  return options.server_minor_version >= 7
+
 ######################################################################
 
 

Modified: subversion/branches/performance/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/svntest/wc.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/svntest/wc.py Sun Sep 26 11:58:58 2010
@@ -836,18 +836,23 @@ def text_base_path(file_path):
     relpath = os.path.join(tail, relpath).replace(os.sep, '/')
 
   c = db.cursor()
-  c.execute("""select checksum from working_node
-               where local_relpath = '""" + relpath + """'""")
-  checksum = c.fetchone()
-  if checksum is None:
+  # NODES conversion is complete enough that we can use it if it exists
+  c.execute("""pragma table_info(nodes)""")
+  if c.fetchone():
+    c.execute("""select checksum from nodes
+                 where local_relpath = '""" + relpath + """'
+                 and op_depth = 0""")
+  else:
     c.execute("""select checksum from base_node
                  where local_relpath = '""" + relpath + """'""")
-    checksum = c.fetchone()[0]
-  if checksum is not None and checksum[0:6] == "$md5 $":
-    c.execute("""select checksum from pristine
-                 where md5_checksum = '""" + checksum + """'""")
-    checksum = c.fetchone()[0]
-  if checksum is None:
+  row = c.fetchone()
+  if row is not None:
+    checksum = row[0]
+    if checksum is not None and checksum[0:6] == "$md5 $":
+      c.execute("""select checksum from pristine
+                   where md5_checksum = '""" + checksum + """'""")
+      checksum = c.fetchone()[0]
+  if row is None or checksum is None:
     raise svntest.Failure("No SHA1 checksum for " + relpath)
   db.close()
 
@@ -858,8 +863,7 @@ def text_base_path(file_path):
   if os.path.isfile(fn):
     return fn
 
-  # Calculate per dir location
-  return os.path.join(root_path, dot_svn, 'pristine', checksum)
+  raise svntest.Failure("No pristine text for " + relpath)
 
 
 # ------------

Modified: subversion/branches/performance/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/switch_tests.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/switch_tests.py Sun Sep 26 11:58:58 2010
@@ -1049,18 +1049,25 @@ def commit_mods_below_switch(sbox):
 
 def relocate_beyond_repos_root(sbox):
   "relocate with prefixes longer than repo root"
-  sbox.build(read_only = True)
+  sbox.build(read_only=True, create_wc=False)
+
+  wc_backup = sbox.add_wc_path('backup')
 
   wc_dir = sbox.wc_dir
   repo_dir = sbox.repo_dir
   repo_url = sbox.repo_url
   other_repo_dir, other_repo_url = sbox.add_repo_path('other')
-  svntest.main.copy_repos(repo_dir, other_repo_dir, 1, 0)
-
   A_url = repo_url + "/A"
+  A_wc_dir = wc_dir
   other_A_url = other_repo_url + "/A"
   other_B_url = other_repo_url + "/B"
-  A_wc_dir = os.path.join(wc_dir, "A")
+
+  svntest.main.safe_rmtree(wc_dir, 1)
+  svntest.actions.run_and_verify_svn(None, None, [], 'checkout',
+                                     repo_url + '/A', wc_dir)
+  
+  svntest.main.copy_repos(repo_dir, other_repo_dir, 1, 0)
+  
 
   # A relocate that changes the repo path part of the URL shouldn't work.
   # This tests for issue #2380.
@@ -2959,7 +2966,7 @@ def single_file_relocate(sbox):
   svntest.main.copy_repos(repo_dir, other_repo_dir, 1, 0)
   svntest.main.safe_rmtree(repo_dir, 1)
   svntest.actions.run_and_verify_svn(None, None,
-                                     ".*Cannot relocate a single file\n",
+                                     ".*Cannot relocate.*",
                                      'switch', '--relocate',
                                      iota_url, other_iota_url, iota_path)
 

Modified: subversion/branches/performance/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_fs/fs-test.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_fs/fs-test.c Sun Sep 26 11:58:58 2010
@@ -586,12 +586,12 @@ list_directory(const svn_test_opts_t *op
 }
 
 
-/* If EXPR raises SVN_ERR_BAD_OLD_VALUE, continue; else, fail
+/* If EXPR raises SVN_ERR_FS_PROP_BASEVALUE_MISMATCH, continue; else, fail
  * the test. */
 #define FAILS_WITH_BOV(expr) \
   do { \
       svn_error_t *__err = (expr); \
-      if (!__err || __err->apr_err != SVN_ERR_BAD_OLD_VALUE) \
+      if (!__err || __err->apr_err != SVN_ERR_FS_PROP_BASEVALUE_MISMATCH) \
         return svn_error_create(SVN_ERR_TEST_FAILED, __err, \
                                 "svn_fs_change_rev_prop2() failed to " \
                                 "detect unexpected old value"); \

Modified: subversion/branches/performance/subversion/tests/libsvn_subr/cache-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_subr/cache-test.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_subr/cache-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_subr/cache-test.c Sun Sep 26 11:58:58 2010
@@ -55,11 +55,12 @@ deserialize_revnum(void **out,
                    apr_size_t data_len,
                    apr_pool_t *pool)
 {
-  svn_revnum_t *in_rev, *out_rev;
+  const svn_revnum_t *in_rev = (const svn_revnum_t *) data;
+  svn_revnum_t *out_rev;
+
   if (data_len != sizeof(*in_rev))
     return svn_error_create(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
                             _("Bad size for revision number in cache"));
-  in_rev = (svn_revnum_t *) data;
   out_rev = apr_palloc(pool, sizeof(*out_rev));
   *out_rev = *in_rev;
   *out = out_rev;

Modified: subversion/branches/performance/subversion/tests/libsvn_subr/target-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_subr/target-test.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_subr/target-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_subr/target-test.c Sun Sep 26 11:58:58 2010
@@ -64,7 +64,8 @@ condense_targets_tests_helper(const char
   apr_array_header_t *targets;
   apr_array_header_t *condensed_targets;
   const char *common_path, *common_path2, *curdir;
-  char *token, *iter, *exp_common_abs = (char*)exp_common;
+  char *token, *iter;
+  const char *exp_common_abs = exp_common;
   int i;
   char buf[8192];
 

Modified: subversion/branches/performance/subversion/tests/libsvn_wc/db-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_wc/db-test.c?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_wc/db-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_wc/db-test.c Sun Sep 26 11:58:58 2010
@@ -419,7 +419,7 @@ static const char * const TESTING_DATA =
   "  null, null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-d', 1, 'J', 2, 'moved/file', 2, 'normal', null,"
-  "  1, null, 'file', 2, " TIME_2s ", '" AUTHOR_2 "', '$md5 $ " MD5_1 " ',"
+  "  1, null, 'file', 2, " TIME_2s ", '" AUTHOR_2 "', '$md5 $" MD5_1 "',"
   " '()', 10, null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e', 1, 'J', null, null, null, 'not-present', null,"
@@ -486,17 +486,15 @@ static const char * const TESTING_DATA =
    "  null, null, null, null, null, "
    "  null, null, null, 0, null, null, '()', 0); "
 #endif
-#ifdef SVN_WC__NODES_not_enabled_yet
+#ifdef SVN_WC__NODES
    "insert into nodes values ("
-   "  1, 'M', null, null, '', 'normal', 'dir', "
-   "  1, null, null, "
-   "  1, " TIME_1s ", '" AUTHOR_1 "', null, null, null, '()', null, null, "
-   "  null); "
+   "  1, 'M', 0, '', null, null, null, 'normal', null, "
+   "  1, null, 'dir', 1, " TIME_1s ", '" AUTHOR_1 "', null, '()', "
+   "  null, null, null, null, null);"
    "insert into nodes values ("
-   "  1, 'M/M-a', 'M', 'not-present', 'file', "
-   "  null, null, "
-   "  null, null, null, null, null, "
-   "  null, null, null, 0, null, null, '()', 0); "
+   "  1, 'M/M-a', 1, 'M', null, null, null, 'not-present', null, "
+   "  null, null, 'file', null, null, null, null, '()', "
+   "  null, 0, null, null, null);"
 #endif
    );
 

Modified: subversion/branches/performance/tools/client-side/svnmucc/svnmucc-test.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/tools/client-side/svnmucc/svnmucc-test.py?rev=1001417&r1=1001416&r2=1001417&view=diff
==============================================================================
--- subversion/branches/performance/tools/client-side/svnmucc/svnmucc-test.py (original)
+++ subversion/branches/performance/tools/client-side/svnmucc/svnmucc-test.py Sun Sep 26 11:58:58 2010
@@ -34,6 +34,10 @@ this_dir = os.path.dirname(os.path.abspa
 sys.path.insert(0, '%s/../../../subversion/tests/cmdline' % (this_dir))
 import svntest
 
+# setup the global 'svntest.main.options' object so functions in the
+# module don't freak out.
+svntest.main._parse_options(arglist=[])
+
 # calculate the top of the build tree
 if len(sys.argv) > 1:
   build_top = os.path.abspath(sys.argv[1])
@@ -275,6 +279,13 @@ def main():
   run_svnmucc(['M /foo/bar'], #---------
               'propdel', 'testprop', 'foo/bar')
 
+  # revision 18
+  run_svnmucc(['M /foo/z.c',
+               'M /foo/foo',
+               ], #---------
+              'propset', 'testprop', 'true', 'foo/z.c',
+              'propset', 'testprop', 'true', 'foo/foo')
+
   # Expected missing revision error
   xrun_svnmucc(['svnmucc: \'a\' is not a revision'
                 ], #---------