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 [9/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/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/svnserve/svnserve.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/log-addressing/subversion/svnserve/svnserve.c Tue Oct 15 23:44:41 2013
@@ -54,6 +54,22 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_cmdline_private.h"
 #include "private/svn_atomic.h"
+#include "private/svn_mutex.h"
+#include "private/svn_subr_private.h"
+
+/* Alas! old APR-Utils don't provide thread pools */
+#if APR_HAS_THREADS
+#  if APR_VERSION_AT_LEAST(1,3,0)
+#    include <apr_thread_pool.h>
+#    define HAVE_THREADPOOLS 1
+#    define THREAD_ERROR_MSG _("Can't push task")
+#  else
+#    define HAVE_THREADPOOLS 0
+#    define THREAD_ERROR_MSG _("Can't create thread")
+#  endif
+#else
+#  define HAVE_THREADPOOLS 0
+#endif
 
 #include "winservice.h"
 
@@ -62,6 +78,7 @@
 #endif
 
 #include "server.h"
+#include "logger.h"
 
 /* The strategy for handling incoming connections.  Some of these may be
    unavailable due to platform limitations. */
@@ -102,6 +119,50 @@ enum run_mode {
 
 #endif
 
+/* Parameters for the worker thread pool used in threaded mode. */
+
+/* Have at least this many worker threads (even if there are no requests
+ * to handle).
+ *
+ * A 0 value is legal but increases the latency for the next incoming
+ * request.  Higher values may be useful for servers that experience short
+ * bursts of concurrent requests followed by longer idle periods.
+ */
+#define THREADPOOL_MIN_SIZE 1
+
+/* Maximum number of worker threads.  If there are more concurrent requests
+ * than worker threads, the extra requests get queued.
+ *
+ * Since very slow connections will hog a full thread for a potentially
+ * long time before timing out, be sure to not set this limit too low.
+ * 
+ * On the other hand, keep in mind that every thread will allocate up to
+ * 4MB of unused RAM in the APR allocator of its root pool.  32 bit servers
+ * must hence do with fewer threads.
+ */
+#if (APR_SIZEOF_VOIDP <= 4)
+#define THREADPOOL_MAX_SIZE 64
+#else
+#define THREADPOOL_MAX_SIZE 256
+#endif
+
+/* Number of microseconds that an unused thread remains in the pool before
+ * being terminated.
+ *
+ * Higher values are useful if clients frequently send small requests and
+ * you want to minimize the latency for those.
+ */
+#define THREADPOOL_THREAD_IDLE_LIMIT 1000000
+
+/* Number of client to server connections that may concurrently in the
+ * TCP 3-way handshake state, i.e. are in the process of being created.
+ *
+ * Larger values improve scalability with lots of small requests comming
+ * on over long latency networks.
+ * 
+ * The OS may actually use a lower limit than specified here.
+ */
+#define ACCEPT_BACKLOG 128
 
 #ifdef WIN32
 static apr_os_sock_t winservice_svnserve_accept_socket = INVALID_SOCKET;
@@ -291,7 +352,6 @@ static const apr_getopt_option_t svnserv
     {0,                  0,   0, 0}
   };
 
-
 static void usage(const char *progname, apr_pool_t *pool)
 {
   if (!progname)
@@ -310,15 +370,21 @@ static void help(apr_pool_t *pool)
 #ifdef WIN32
   svn_error_clear(svn_cmdline_fputs(_("usage: svnserve [-d | -i | -t | -X "
                                       "| --service] [options]\n"
+                                      "Subversion repository server.\n"
+                                      "Type 'svnserve --version' to see the "
+                                      "program version.\n"
                                       "\n"
                                       "Valid options:\n"),
-                                    stdout, pool));
+                                      stdout, pool));
 #else
   svn_error_clear(svn_cmdline_fputs(_("usage: svnserve [-d | -i | -t | -X] "
                                       "[options]\n"
+                                      "Subversion repository server.\n"
+                                      "Type 'svnserve --version' to see the "
+                                      "program version.\n"
                                       "\n"
                                       "Valid options:\n"),
-                                    stdout, pool));
+                                      stdout, pool));
 #endif
   for (i = 0; svnserve__options[i].name && svnserve__options[i].optch; i++)
     {
@@ -388,17 +454,20 @@ static apr_status_t redirect_stdout(void
    So we set the atomic counter to 2 then both the calling thread and
    the new thread decrease it and when it reaches 0 the pool can be
    released.  */
-struct shared_pool_t {
+typedef struct shared_pool_t {
   svn_atomic_t count;
-  apr_pool_t *pool;
-};
-
-static struct shared_pool_t *
-attach_shared_pool(apr_pool_t *pool)
+  apr_pool_t *pool;              /* root pool used to allocate the socket */
+  svn_root_pools__t *root_pools; /* put it back into this after use */
+} shared_pool_t;
+
+static shared_pool_t *
+attach_shared_pool(apr_pool_t *pool,
+                   svn_root_pools__t *root_pools)
 {
-  struct shared_pool_t *shared = apr_palloc(pool, sizeof(struct shared_pool_t));
+  shared_pool_t *shared = apr_palloc(pool, sizeof(*shared));
 
   shared->pool = pool;
+  shared->root_pools = root_pools;
   svn_atomic_set(&shared->count, 2);
 
   return shared;
@@ -408,23 +477,75 @@ static void
 release_shared_pool(struct shared_pool_t *shared)
 {
   if (svn_atomic_dec(&shared->count) == 0)
-    svn_pool_destroy(shared->pool);
+    svn_root_pools__release_pool(shared->pool, shared->root_pools);
 }
 #endif
 
+/* Wrapper around serve() that takes a socket instead of a connection.
+ * This is to off-load work from the main thread in threaded and fork modes.
+ */
+static svn_error_t *
+serve_socket(apr_socket_t *usock,
+             serve_params_t *params,
+             apr_pool_t *pool)
+{
+  apr_status_t status;
+  svn_ra_svn_conn_t *conn;
+  svn_error_t *err;
+  
+  /* Enable TCP keep-alives on the socket so we time out when
+   * the connection breaks due to network-layer problems.
+   * If the peer has dropped the connection due to a network partition
+   * or a crash, or if the peer no longer considers the connection
+   * valid because we are behind a NAT and our public IP has changed,
+   * it will respond to the keep-alive probe with a RST instead of an
+   * acknowledgment segment, which will cause svn to abort the session
+   * even while it is currently blocked waiting for data from the peer. */
+  status = apr_socket_opt_set(usock, APR_SO_KEEPALIVE, 1);
+  if (status)
+    {
+      /* It's not a fatal error if we cannot enable keep-alives. */
+    }
+
+  /* create the connection, configure ports etc. */
+  conn = svn_ra_svn_create_conn3(usock, NULL, NULL,
+                                 params->compression_level,
+                                 params->zero_copy_limit,
+                                 params->error_check_interval,
+                                 pool);
+
+  /* process the actual request and log errors */
+  err = serve(conn, params, pool);
+  if (err)
+    logger__log_error(params->logger, err, NULL,
+                      get_client_info(conn, params, pool));
+
+  return svn_error_trace(err);
+}
+
 /* "Arguments" passed from the main thread to the connection thread */
 struct serve_thread_t {
-  svn_ra_svn_conn_t *conn;
+  apr_socket_t *usock;
   serve_params_t *params;
-  struct shared_pool_t *shared_pool;
+#if APR_HAS_THREADS
+  shared_pool_t *shared_pool;
+#endif
 };
 
 #if APR_HAS_THREADS
+
+/* allocate and recycle root pools for connection objects.
+   There should be at most THREADPOOL_MAX_SIZE such pools. */
+svn_root_pools__t *connection_pools;
+
 static void * APR_THREAD_FUNC serve_thread(apr_thread_t *tid, void *data)
 {
   struct serve_thread_t *d = data;
 
-  svn_error_clear(serve(d->conn, d->params, d->shared_pool->pool));
+  apr_pool_t *pool = svn_root_pools__acquire_pool(connection_pools);
+  svn_error_clear(serve_socket(d->usock, d->params, pool));
+  svn_root_pools__release_pool(pool, connection_pools);
+
   release_shared_pool(d->shared_pool);
 
   return NULL;
@@ -478,21 +599,22 @@ int main(int argc, const char *argv[])
   apr_file_t *in_file, *out_file;
   apr_sockaddr_t *sa;
   apr_pool_t *pool;
-  apr_pool_t *connection_pool;
   svn_error_t *err;
   apr_getopt_t *os;
   int opt;
   serve_params_t params;
   const char *arg;
   apr_status_t status;
-  svn_ra_svn_conn_t *conn;
   apr_proc_t proc;
 #if APR_HAS_THREADS
+  shared_pool_t *shared_pool;
+  struct serve_thread_t *thread_data;
+#if HAVE_THREADPOOLS
+  apr_thread_pool_t *threads;
+#else
   apr_threadattr_t *tattr;
   apr_thread_t *tid;
-  struct shared_pool_t *shared_pool;
-
-  struct serve_thread_t *thread_data;
+#endif
 #endif
   enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
   apr_uint16_t port = SVN_RA_SVN_PORT;
@@ -510,6 +632,7 @@ int main(int argc, const char *argv[])
   const char *pid_filename = NULL;
   const char *log_filename = NULL;
   svn_node_kind_t kind;
+  svn_root_pools__t *socket_pools;
 
   /* Initialize the app. */
   if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
@@ -543,7 +666,7 @@ int main(int argc, const char *argv[])
   params.base = NULL;
   params.cfg = NULL;
   params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
-  params.log_file = NULL;
+  params.logger = NULL;
   params.vhost = FALSE;
   params.username_case = CASE_ASIS;
   params.memory_cache_size = (apr_uint64_t)-1;
@@ -799,9 +922,7 @@ int main(int argc, const char *argv[])
     }
 
   if (log_filename)
-    SVN_INT_ERR(svn_io_file_open(&params.log_file, log_filename,
-                                 APR_WRITE | APR_CREATE | APR_APPEND,
-                                 APR_OS_DEFAULT, pool));
+    SVN_INT_ERR(logger__create(&params.logger, log_filename, pool));
 
   if (params.tunnel_user && run_mode != run_mode_tunnel)
     {
@@ -814,6 +935,9 @@ int main(int argc, const char *argv[])
 
   if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
     {
+      apr_pool_t *connection_pool;
+      svn_ra_svn_conn_t *conn;
+
       params.tunnel = (run_mode == run_mode_tunnel);
       apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
                                 redirect_stdout);
@@ -960,7 +1084,7 @@ int main(int argc, const char *argv[])
       return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
     }
 
-  apr_socket_listen(sock, 7);
+  apr_socket_listen(sock, ACCEPT_BACKLOG);
 
 #if APR_HAS_FORK
   if (run_mode != run_mode_listen_once && !foreground)
@@ -1022,8 +1146,45 @@ int main(int argc, const char *argv[])
     svn_cache_config_set(&settings);
   }
 
+  /* we use (and recycle) separate pools for sockets (many small ones)
+     and connections (fewer but larger ones) */
+  err = svn_root_pools__create(&socket_pools);
+  if (err)
+    return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+
+#if APR_HAS_THREADS
+  err = svn_root_pools__create(&connection_pools);
+  if (err)
+    return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+#endif
+
+#if HAVE_THREADPOOLS
+  if (handling_mode == connection_mode_thread)
+    {
+      /* create the thread pool */
+      status = apr_thread_pool_create(&threads,
+                                      THREADPOOL_MIN_SIZE,
+                                      THREADPOOL_MAX_SIZE,
+                                      pool);
+      if (status)
+        {
+          err = svn_error_wrap_apr (status, _("Can't create thread pool"));
+          return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+        }
+
+      /* let idle threads linger for a while in case more requests are
+         coming in */
+      apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);
+
+      /* don't queue requests unless we reached the worker thread limit */
+      apr_thread_pool_threshold_set(threads, 0);
+    }
+#endif
+
   while (1)
     {
+      apr_pool_t *socket_pool;
+
 #ifdef WIN32
       if (winservice_is_stopping())
         return ERROR_SUCCESS;
@@ -1033,22 +1194,21 @@ int main(int argc, const char *argv[])
          the connection threads so it cannot clean up after each one.  So
          separate pools that can be cleared at thread exit are used. */
 
-      connection_pool
-          = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+      socket_pool = svn_root_pools__acquire_pool(socket_pools);
 
-      status = apr_socket_accept(&usock, sock, connection_pool);
+      status = apr_socket_accept(&usock, sock, socket_pool);
       if (handling_mode == connection_mode_fork)
         {
           /* Collect any zombie child processes. */
           while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT,
-                                         connection_pool) == APR_CHILD_DONE)
+                                         socket_pool) == APR_CHILD_DONE)
             ;
         }
       if (APR_STATUS_IS_EINTR(status)
           || APR_STATUS_IS_ECONNABORTED(status)
           || APR_STATUS_IS_ECONNRESET(status))
         {
-          svn_pool_destroy(connection_pool);
+          svn_root_pools__release_pool(socket_pool, socket_pools);
           continue;
         }
       if (status)
@@ -1058,29 +1218,9 @@ int main(int argc, const char *argv[])
           return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
         }
 
-      /* Enable TCP keep-alives on the socket so we time out when
-       * the connection breaks due to network-layer problems.
-       * If the peer has dropped the connection due to a network partition
-       * or a crash, or if the peer no longer considers the connection
-       * valid because we are behind a NAT and our public IP has changed,
-       * it will respond to the keep-alive probe with a RST instead of an
-       * acknowledgment segment, which will cause svn to abort the session
-       * even while it is currently blocked waiting for data from the peer. */
-      status = apr_socket_opt_set(usock, APR_SO_KEEPALIVE, 1);
-      if (status)
-        {
-          /* It's not a fatal error if we cannot enable keep-alives. */
-        }
-
-      conn = svn_ra_svn_create_conn3(usock, NULL, NULL,
-                                     params.compression_level,
-                                     params.zero_copy_limit,
-                                     params.error_check_interval,
-                                     connection_pool);
-
       if (run_mode == run_mode_listen_once)
         {
-          err = serve(conn, &params, connection_pool);
+          err = serve_socket(usock, &params, socket_pool);
 
           if (err)
             svn_handle_error2(err, stdout, FALSE, "svnserve: ");
@@ -1095,16 +1235,11 @@ int main(int argc, const char *argv[])
         {
         case connection_mode_fork:
 #if APR_HAS_FORK
-          status = apr_proc_fork(&proc, connection_pool);
+          status = apr_proc_fork(&proc, socket_pool);
           if (status == APR_INCHILD)
             {
               apr_socket_close(sock);
-              err = serve(conn, &params, connection_pool);
-              log_error(err, params.log_file,
-                        svn_ra_svn_conn_remote_host(conn),
-                        NULL, NULL, /* user, repos */
-                        connection_pool);
-              svn_error_clear(err);
+              svn_error_clear(serve_socket(usock, &params, socket_pool));
               apr_socket_close(usock);
               exit(0);
             }
@@ -1115,14 +1250,11 @@ int main(int argc, const char *argv[])
           else
             {
               err = svn_error_wrap_apr(status, "apr_proc_fork");
-              log_error(err, params.log_file,
-                        svn_ra_svn_conn_remote_host(conn),
-                        NULL, NULL, /* user, repos */
-                        connection_pool);
+              logger__log_error(params.logger, err, NULL, NULL);
               svn_error_clear(err);
               apr_socket_close(usock);
             }
-          svn_pool_destroy(connection_pool);
+          svn_root_pools__release_pool(socket_pool, socket_pools);
 #endif
           break;
 
@@ -1131,8 +1263,17 @@ int main(int argc, const char *argv[])
              particularly sophisticated strategy for a threaded server, it's
              little different from forking one process per connection. */
 #if APR_HAS_THREADS
-          shared_pool = attach_shared_pool(connection_pool);
-          status = apr_threadattr_create(&tattr, connection_pool);
+          shared_pool = attach_shared_pool(socket_pool, socket_pools);
+
+          thread_data = apr_palloc(socket_pool, sizeof(*thread_data));
+          thread_data->usock = usock;
+          thread_data->params = &params;
+          thread_data->shared_pool = shared_pool;
+#if HAVE_THREADPOOLS
+          status = apr_thread_pool_push(threads, serve_thread, thread_data,
+                                        0, NULL);
+#else
+          status = apr_threadattr_create(&tattr, socket_pool);
           if (status)
             {
               err = svn_error_wrap_apr(status, _("Can't create threadattr"));
@@ -1148,15 +1289,12 @@ int main(int argc, const char *argv[])
               svn_error_clear(err);
               exit(1);
             }
-          thread_data = apr_palloc(connection_pool, sizeof(*thread_data));
-          thread_data->conn = conn;
-          thread_data->params = &params;
-          thread_data->shared_pool = shared_pool;
           status = apr_thread_create(&tid, tattr, serve_thread, thread_data,
                                      shared_pool->pool);
+#endif
           if (status)
             {
-              err = svn_error_wrap_apr(status, _("Can't create thread"));
+              err = svn_error_wrap_apr(status, THREAD_ERROR_MSG);
               svn_handle_error2(err, stderr, FALSE, "svnserve: ");
               svn_error_clear(err);
               exit(1);
@@ -1167,8 +1305,8 @@ int main(int argc, const char *argv[])
 
         case connection_mode_single:
           /* Serve one connection at a time. */
-          svn_error_clear(serve(conn, &params, connection_pool));
-          svn_pool_destroy(connection_pool);
+          svn_error_clear(serve_socket(usock, &params, socket_pool));
+          svn_root_pools__release_pool(socket_pool, socket_pools);
         }
     }
 

Modified: subversion/branches/log-addressing/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/svnsync/svnsync.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/log-addressing/subversion/svnsync/svnsync.c Tue Oct 15 23:44:41 2013
@@ -1846,6 +1846,7 @@ help_cmd(apr_getopt_t *os, void *baton, 
 
   const char *header =
     _("general usage: svnsync SUBCOMMAND DEST_URL  [ARGS & OPTIONS ...]\n"
+      "Subversion repository replication tool.\n"
       "Type 'svnsync help <subcommand>' for help on a specific subcommand.\n"
       "Type 'svnsync --version' to see the program version and RA modules.\n"
       "\n"

Modified: subversion/branches/log-addressing/subversion/svnversion/svnversion.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/svnversion/svnversion.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/svnversion/svnversion.c (original)
+++ subversion/branches/log-addressing/subversion/svnversion/svnversion.c Tue Oct 15 23:44:41 2013
@@ -57,7 +57,10 @@ help(const apr_getopt_option_t *options,
   svn_error_clear
     (svn_cmdline_fprintf
      (stdout, pool,
-      _("usage: svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]\n\n"
+      _("usage: svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]\n"
+        "Subversion working copy identification tool.\n"
+        "Type 'svnversion --version' to see the program version.\n"
+        "\n"
         "  Produce a compact version identifier for the working copy path\n"
         "  WC_PATH.  TRAIL_URL is the trailing portion of the URL used to\n"
         "  determine if WC_PATH itself is switched (detection of switches\n"

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/authz_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/authz_tests.py Tue Oct 15 23:44:41 2013
@@ -1551,6 +1551,44 @@ def log_diff_dontdothat(sbox):
                                       'log', ddt_url,
                                       '-c', 1, '--diff')
 
+@Issue(4422)
+@Skip(svntest.main.is_ra_type_file)
+def authz_file_external_to_authz(sbox):
+  "replace file external with authz node"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  repo_url = sbox.repo_url
+
+  write_authz_file(sbox, {"/": "* = rw"})
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+
+  sbox.simple_propset('svn:externals', 'Z ' + repo_url + '/iota', '')
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('', status=' M')
+  expected_status.add({
+    'Z' : Item(status='  ', wc_rev='1', switched='X'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        None, None, expected_status)
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'cp', repo_url + '/A',
+                                           repo_url + '/Z',
+                                      '-m', 'Add Z')
+
+  write_authz_file(sbox, {"/": "* = rw", "/Z": "* = "})
+
+  expected_status.tweak(wc_rev=2)
+
+  # ### This used to assert with
+  # ### svn: E235000: In file 'update_editor.c' line 3043: assertion failed
+  # ###               (status != svn_wc__db_status_normal)
+
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        None, None, expected_status)
+
 
 ########################################################################
 # Run the tests
@@ -1585,6 +1623,7 @@ test_list = [ None,
               authz_svnserve_groups,
               authz_del_from_subdir,
               log_diff_dontdothat,
+              authz_file_external_to_authz,
              ]
 serial_only = True
 

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/checkout_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/checkout_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/checkout_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/checkout_tests.py Tue Oct 15 23:44:41 2013
@@ -1057,7 +1057,7 @@ def checkout_wc_from_drive(sbox):
   svntest.main.safe_rmtree(sbox.wc_dir)
   os.mkdir(sbox.wc_dir)
 
-  # create a virtual drive to the working copy folder
+  # create a virtual drive to the repository folder
   drive = find_the_next_available_drive_letter()
   if drive is None:
     raise svntest.Skip
@@ -1093,8 +1093,49 @@ def checkout_wc_from_drive(sbox):
     })
     svntest.actions.run_and_verify_checkout(repo_url, wc_dir,
                                             expected_output, expected_wc,
-                                            None, None, None, None,
-                                            '--force')
+                                            None, None, None, None)
+
+    wc2_dir = sbox.add_wc_path('2')
+    expected_output = wc.State(wc2_dir, {
+      'D'                 : Item(status='A '),
+      'D/H'               : Item(status='A '),
+      'D/H/psi'           : Item(status='A '),
+      'D/H/chi'           : Item(status='A '),
+      'D/H/omega'         : Item(status='A '),
+      'D/G'               : Item(status='A '),
+      'D/G/tau'           : Item(status='A '),
+      'D/G/pi'            : Item(status='A '),
+      'D/G/rho'           : Item(status='A '),
+      'D/gamma'           : Item(status='A '),
+      'C'                 : Item(status='A '),
+      'mu'                : Item(status='A '),
+      'B'                 : Item(status='A '),
+      'B/E'               : Item(status='A '),
+      'B/E/alpha'         : Item(status='A '),
+      'B/E/beta'          : Item(status='A '),
+      'B/F'               : Item(status='A '),
+      'B/lambda'          : Item(status='A '),
+    })
+    svntest.actions.run_and_verify_checkout(repo_url + '/A', wc2_dir,
+                                            expected_output, None,
+                                            None, None, None, None)
+
+    wc3_dir = sbox.add_wc_path('3')
+    expected_output = wc.State(wc3_dir, {
+      'H'                 : Item(status='A '),
+      'H/psi'             : Item(status='A '),
+      'H/chi'             : Item(status='A '),
+      'H/omega'           : Item(status='A '),
+      'G'                 : Item(status='A '),
+      'G/tau'             : Item(status='A '),
+      'G/pi'              : Item(status='A '),
+      'G/rho'             : Item(status='A '),
+      'gamma'             : Item(status='A '),
+    })
+
+    svntest.actions.run_and_verify_checkout(repo_url + '/A/D', wc3_dir,
+                                            expected_output, None,
+                                            None, None, None, None)
 
   finally:
     os.chdir(was_cwd)

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/commit_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/commit_tests.py Tue Oct 15 23:44:41 2013
@@ -1250,7 +1250,7 @@ def commit_add_file_twice(sbox):
   svntest.actions.run_and_verify_commit(wc_dir,
                                         None,
                                         None,
-                                        "already exists",
+                                        "E160020: File.*already exists",
                                         wc_dir)
 
 #----------------------------------------------------------------------

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/externals_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/externals_tests.py Tue Oct 15 23:44:41 2013
@@ -3264,6 +3264,89 @@ def switch_parent_relative_file_external
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'update', branch_wc)
 
+@Issue(4420)
+def file_external_unversioned_obstruction(sbox):
+  """file externals unversioned obstruction"""
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  expected_output = verify.RegexOutput('r2 committed .*')
+  svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                           '-U', sbox.repo_url, '-m', 'r2: set external',
+                           'propset', 'svn:externals', '^/A/mu mu-ext', 'A')
+
+  sbox.simple_append('A/mu-ext', 'unversioned obstruction')
+
+  # Update reports a tree-conflict but status doesn't show any such
+  # conflict.  I'm no sure whether this is correct.
+  expected_output = svntest.wc.State(wc_dir, {
+      'A'        : Item(status=' U'),
+      'A/mu-ext' : Item(status='  ', treeconflict='A'),
+      })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+      'A/mu-ext' : Item('unversioned obstruction'),
+      })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+      'A/mu-ext' : Item(status='M ', wc_rev='2', switched='X'),
+      })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, expected_disk,
+                                        expected_status)
+
+@Issue(4001)
+@XFail()
+def file_external_versioned_obstruction(sbox):
+  """file externals versioned obstruction"""
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  expected_output = verify.RegexOutput('r2 committed .*')
+  svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                           '-U', sbox.repo_url, '-m', 'r2: set external',
+                           'propset', 'svn:externals', '^/A/mu mu-ext', 'A')
+
+  expected_output = svntest.wc.State(wc_dir, {
+      'A'        : Item(status=' U'),
+      'A/mu-ext' : Item(status='A '),
+      })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+      'A/mu-ext' : Item('This is the file \'mu\'.\n'),
+      })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+      'A/mu-ext' : Item(status='  ', wc_rev='2', switched='X'),
+      })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, expected_disk,
+                                        expected_status)
+
+  # Update skips adding the versioned node because of the file
+  # external obstruction then when the external is deleted the
+  # versioned node is missing from disk and wc.db.  Not really sure
+  # what should happen, perhaps a not-present node?
+  expected_output = verify.RegexOutput('r3 committed .*')
+  svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                           '-U', sbox.repo_url, '-m', 'r3: copy file',
+                           'cp', 'head', 'A/mu', 'A/mu-ext',
+                           'propdel', 'svn:externals', 'A')
+
+  expected_output = svntest.wc.State(wc_dir, {
+      'A'        : Item(status=' U'),
+      'A/mu-ext' : Item(verb='Removed external', prev_verb='Skipped'),
+      })
+  expected_disk.tweak('A/mu-ext', content='This is the file \'mu\'.\n')
+  expected_status.tweak(wc_rev=3)
+  expected_status.tweak('A/mu-ext', switched=None)
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, expected_disk,
+                                        expected_status)
+
+
 ########################################################################
 # Run the tests
 
@@ -3317,6 +3400,8 @@ test_list = [ None,
               pinned_externals,
               update_dir_external_shallow,
               switch_parent_relative_file_external,
+              file_external_unversioned_obstruction,
+              file_external_versioned_obstruction,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests.py Tue Oct 15 23:44:41 2013
@@ -90,13 +90,6 @@ rep_lines_res = [
                  # In 'svn --version --quiet', we print only the version
                  # number in a single line.
                  (re.compile(r'^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$'), 'X.Y.Z\n'),
-                 # 'svn --help' has a line with the version number.
-                 # It can vary, for example:
-                 # "Subversion command-line client, version 1.1.0."
-                 # "Subversion command-line client, version 1.1.0-dev."
-                 (re.compile(r'Subversion command-line client, '
-                             'version \d+\.\d+\.\d+(.|-[a-zA-Z0-9]+\.)$'),
-                  'Subversion command-line client, version X.Y.Z.'),
                 ]
 
 # This is a trigger pattern that selects the secondary set of

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Tue Oct 15 23:44:41 2013
@@ -1,5 +1,5 @@
 usage: svn <subcommand> [options] [args]
-Subversion command-line client, version X.Y.Z.
+Subversion command-line client.
 Type 'svn help <subcommand>' for help on a specific subcommand.
 Type 'svn --version' to see the program version and RA modules
   or 'svn --version --quiet' to see just the version number.

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Tue Oct 15 23:44:41 2013
@@ -95,6 +95,8 @@ Valid options:
   --with-all-revprops      : retrieve all revision properties
   --with-no-revprops       : retrieve no revision properties
   --with-revprop ARG       : retrieve revision property ARG
+  --auto-moves             : attempt to interpret matching unique DEL+ADD
+                             pairs as moves
   --depth ARG              : limit operation by depth ARG ('empty', 'files',
                              'immediates', or 'infinity')
   --diff                   : produce diff output

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Tue Oct 15 23:44:41 2013
@@ -1,5 +1,5 @@
 usage: svn <subcommand> [options] [args]
-Subversion command-line client, version X.Y.Z.
+Subversion command-line client.
 Type 'svn help <subcommand>' for help on a specific subcommand.
 Type 'svn --version' to see the program version and RA modules
   or 'svn --version --quiet' to see just the version number.

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/log_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/log_tests.py Tue Oct 15 23:44:41 2013
@@ -2184,6 +2184,7 @@ def log_diff(sbox):
   compare_diff_output(r9diff, log_chain[1]['diff_lines'])
   compare_diff_output(r8diff, log_chain[2]['diff_lines'])
 
+@Skip(svntest.main.is_fs_type_fsx)
 def log_xml_old(sbox):
   "log --xml shows kind for old style repository"
 

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/move_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/move_tests.py Tue Oct 15 23:44:41 2013
@@ -1338,6 +1338,191 @@ def nested_replaces(sbox):
   svntest.main.run_svn(None, 'update', '-r1', wc_dir)
   svntest.actions.run_and_verify_status(wc_dir, r1_status)
 
+def setup_move_many(sbox):
+  "helper function which creates a wc with node A/A/A which is moved 3 times"
+
+  sbox.simple_rm('A', 'iota')
+  sbox.simple_mkdir('A',
+                    'A/A',
+                    'A/A/A',
+                    'A/A/A/A',
+                    'B',
+                    'B/A',
+                    'B/A/A',
+                    'B/A/A/A',
+                    'C',
+                    'C/A',
+                    'C/A/A',
+                    'C/A/A/A')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  sbox.simple_move('A/A/A', 'AAA_1')
+
+  sbox.simple_rm('A')
+  sbox.simple_move('B', 'A')
+
+  sbox.simple_move('A/A/A', 'AAA_2')
+
+  sbox.simple_rm('A/A')
+  sbox.simple_move('C/A', 'A/A')
+
+  sbox.simple_move('A/A/A', 'AAA_3')
+
+def move_many_status(wc_dir):
+  "obtain standard status after setup_move_many"
+
+  return svntest.wc.State(wc_dir, {
+      ''                  : Item(status='  ', wc_rev='2'),
+
+      'AAA_1'             : Item(status='A ', copied='+', moved_from='A/A/A', wc_rev='-'),
+      'AAA_1/A'           : Item(status='  ', copied='+', wc_rev='-'),
+
+      'AAA_2'             : Item(status='A ', copied='+', moved_from='A/A/A', wc_rev='-'),
+      'AAA_2/A'           : Item(status='  ', copied='+', wc_rev='-'),
+
+      'AAA_3'             : Item(status='A ', copied='+', moved_from='A/A/A', wc_rev='-'),
+      'AAA_3/A'           : Item(status='  ', copied='+', wc_rev='-'),
+
+      'A'                 : Item(status='R ', copied='+', moved_from='B', wc_rev='-'),
+      'A/A'               : Item(status='R ', copied='+', moved_from='C/A', wc_rev='-'),
+      'A/A/A'             : Item(status='D ', copied='+', wc_rev='-', moved_to='AAA_3'),
+      'A/A/A/A'           : Item(status='D ', copied='+', wc_rev='-'),
+
+      'B'                 : Item(status='D ', wc_rev='2', moved_to='A'),
+      'B/A'               : Item(status='D ', wc_rev='2'),
+      'B/A/A'             : Item(status='D ', wc_rev='2'),
+      'B/A/A/A'           : Item(status='D ', wc_rev='2'),
+
+      'C'                 : Item(status='  ', wc_rev='2'),
+      'C/A'               : Item(status='D ', wc_rev='2', moved_to='A/A'),
+      'C/A/A'             : Item(status='D ', wc_rev='2'),
+      'C/A/A/A'           : Item(status='D ', wc_rev='2'),
+    })
+
+def move_many_update_delete(sbox):
+  "move many and delete-on-update"
+
+  sbox.build()
+  setup_move_many(sbox)
+
+  wc_dir = sbox.wc_dir
+
+  # Verify start situation
+  expected_status = move_many_status(wc_dir)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  # And now create a tree conflict
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'rm', sbox.repo_url + '/B',
+                                     '-m', '')
+
+  expected_output = svntest.wc.State(wc_dir, {
+     'B'                 : Item(status='  ', treeconflict='C'),
+    })
+
+
+  expected_status.tweak('', 'C', 'C/A', 'C/A/A', 'C/A/A/A', wc_rev='3')
+  expected_status.tweak('A', moved_from=None)
+  expected_status.remove('B/A', 'B/A/A', 'B/A/A/A')
+  expected_status.tweak('B', status='! ', treeconflict='C', wc_rev=None, moved_to=None)
+
+  svntest.actions.run_and_verify_update(wc_dir, expected_output, None,
+                                        expected_status)
+
+  # Would be nice if we could run the resolver as a separate step, 
+  # but 'svn resolve' just fails for any value but working
+
+@XFail()
+def move_many_update_add(sbox):
+  "move many and add-on-update"
+
+  sbox.build()
+  setup_move_many(sbox)
+
+  wc_dir = sbox.wc_dir
+
+  # Verify start situation
+  expected_status = move_many_status(wc_dir)
+  #svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  # And now create a tree conflict
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'mkdir', sbox.repo_url + '/B/A/A/BB',
+                                     '-m', '')
+
+  expected_output = svntest.wc.State(wc_dir, {
+     'B'                 : Item(status='  ', treeconflict='C'),
+     'B/A'               : Item(status='  ', treeconflict='U'),
+     'B/A/A'             : Item(status='  ', treeconflict='U'),
+     'B/A/A/BB'          : Item(status='  ', treeconflict='A'),
+     # And while resolving
+     'A/A/'              : Item(status='  ', treeconflict='C')
+    })
+
+  expected_status.tweak('',
+                        'B', 'B/A', 'B/A/A', 'B/A/A/A',
+                        'C', 'C/A', 'C/A/A', 'C/A/A/A',
+                        wc_rev='3')
+
+  expected_status.tweak('A/A', treeconflict='C')
+  expected_status.add({
+        'A/A/A/BB'          : Item(status='D ', copied='+', wc_rev='-'),
+        'B/A/A/BB'          : Item(status='D ', wc_rev='3'),
+    })
+
+  svntest.actions.run_and_verify_update(wc_dir, expected_output, None,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, None,
+                                        wc_dir, '--accept', 'mine-conflict')
+
+  # And another one
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'mkdir', sbox.repo_url + '/C/A/A/BB',
+                                     '-m', '')
+
+  expected_status.tweak('',
+                        'B', 'B/A', 'B/A/A', 'B/A/A/A',
+                        'C', 'C/A', 'C/A/A', 'C/A/A/A',
+                        wc_rev='4')
+
+  expected_output = svntest.wc.State(wc_dir, {
+     'C/A'               : Item(status='  ', treeconflict='C'),
+     'C/A/A'             : Item(status='  ', treeconflict='U'),
+     'C/A/A/BB'          : Item(status='  ', treeconflict='A'),
+    })
+
+  # This currently triggers an assertion failure
+  svntest.actions.run_and_verify_update(wc_dir, expected_output, None,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, None,
+                                        wc_dir, '--accept', 'mine-conflict')
+
+@Issue(4437)
+@XFail()
+def move_del_moved(sbox):
+  "delete moved node, still a move"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_mkdir('A/NEW')
+  sbox.simple_move('A/mu', 'A/NEW/mu')
+  sbox.simple_rm('A/NEW/mu')
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='D ')
+  expected_status.add({
+      'A/NEW' : Item(status='A ', wc_rev='-')
+    })
+
+  # A/mu still reports that it is moved to A/NEW/mu, while it is already
+  # deleted there.
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+
 #######################################################################
 # Run the tests
 
@@ -1350,6 +1535,9 @@ test_list = [ None,
               property_merge,
               move_missing,
               nested_replaces,
+              move_many_update_delete,
+              move_many_update_add,
+              move_del_moved,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/revert_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/revert_tests.py Tue Oct 15 23:44:41 2013
@@ -1644,6 +1644,8 @@ def revert_obstructing_wc(sbox):
                                      'revert', '-R', wc_dir)
 
 
+
+
 ########################################################################
 # Run the tests
 
@@ -1683,7 +1685,7 @@ test_list = [ None,
               revert_no_text_change_conflict_recursive,
               revert_with_unversioned_targets,
               revert_nonexistent,
-              revert_obstructing_wc
+              revert_obstructing_wc,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/tree_conflict_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/tree_conflict_tests.py Tue Oct 15 23:44:41 2013
@@ -1455,6 +1455,67 @@ def update_dir_with_not_present(sbox):
   run_and_verify_svn(None, None, [],
                      'ci', '-m', '', wc_dir)
 
+@XFail()
+def update_delete_mixed_rev(sbox):
+  "update that deletes mixed-rev"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  sbox.simple_move('A/B/E/alpha', 'A/B/E/alpha2')
+  sbox.simple_commit()
+  sbox.simple_update()
+  sbox.simple_rm('A/B')
+  sbox.simple_commit()
+  sbox.simple_update(revision=1)
+  sbox.simple_update(target='A/B/E', revision=2)
+  sbox.simple_mkdir('A/B/E2')
+
+  # Update raises a tree conflict on A/B due to local mod A/B/E2
+  expected_output = wc.State(wc_dir, {
+      'A/B' : Item(status='  ', treeconflict='C'),
+      })
+  expected_disk = main.greek_state.copy()
+  expected_disk.add({
+      'A/B/E2'       : Item(),
+      'A/B/E/alpha2' : Item(contents='This is the file \'alpha\'.\n'),
+    })
+  expected_disk.remove('A/B/E/alpha')
+  expected_status = get_virginal_state(wc_dir, 3)
+  expected_status.remove('A/B/E/alpha')
+  expected_status.add({
+      'A/B/E2'       : Item(status='A ', wc_rev='-'),
+      'A/B/E/alpha2' : Item(status='  ', copied='+', wc_rev='-'),
+      })
+  expected_status.tweak('A/B',
+                        status='A ', copied='+', treeconflict='C', wc_rev='-')
+  expected_status.tweak('A/B/F', 'A/B/E', 'A/B/E/beta', 'A/B/lambda',
+                        copied='+', wc_rev='-')
+  run_and_verify_update(wc_dir,
+                        expected_output, expected_disk, expected_status,
+                        None, None, None, None, None, 1,
+                        wc_dir)
+
+  # Resolving to working state should give a mixed-revision copy that
+  # gets committed as multiple copies
+  run_and_verify_resolved([sbox.ospath('A/B')], sbox.ospath('A/B'))
+  expected_output = wc.State(wc_dir, {
+      'A/B'    : Item(verb='Adding'),
+      'A/B/E'  : Item(verb='Replacing'),
+      'A/B/E2' : Item(verb='Adding'),
+      })
+  expected_status.tweak('A/B', 'A/B/E', 'A/B/E2', 'A/B/F', 'A/B/E/alpha2',
+                        'A/B/E/beta', 'A/B/lambda',
+                        status='  ', wc_rev=4, copied=None, treeconflict=None)
+  run_and_verify_commit(wc_dir,
+                        expected_output, expected_status, None,
+                        wc_dir)
+
+  expected_info = {
+    'Name': 'alpha2',
+    'Node Kind': 'file',
+  }
+  run_and_verify_info([expected_info], sbox.repo_url + '/A/B/E/alpha2')
+
 #######################################################################
 # Run the tests
 
@@ -1485,6 +1546,7 @@ test_list = [ None,
               at_directory_external,
               actual_only_node_behaviour,
               update_dir_with_not_present,
+              update_delete_mixed_rev,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/log-addressing/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/cmdline/upgrade_tests.py?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/log-addressing/subversion/tests/cmdline/upgrade_tests.py Tue Oct 15 23:44:41 2013
@@ -430,7 +430,10 @@ def basic_upgrade_1_0(sbox):
 
   url = sbox.repo_url
 
-  xml_entries_relocate(sbox.wc_dir, 'file:///1.0.0/repos', url)
+  # This is non-canonical by the rules of svn_uri_canonicalize, it gets
+  # written into the entries file and upgrade has to canonicalize.
+  non_canonical_url = url[:-1] + '%%%02x' % ord(url[-1])
+  xml_entries_relocate(sbox.wc_dir, 'file:///1.0.0/repos', non_canonical_url)
 
   # Attempt to use the working copy, this should give an error
   expected_stderr = wc_is_too_old_regex

Propchange: subversion/branches/log-addressing/subversion/tests/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/tests/libsvn_fs_x:r1516632-1532579
  Merged /subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_x:r1499981-1509278,1516645-1532583

Propchange: subversion/branches/log-addressing/subversion/tests/libsvn_fs_x/string-table-test.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_ra/ra-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_ra/ra-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_ra/ra-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_ra/ra-test.c Tue Oct 15 23:44:41 2013
@@ -25,17 +25,23 @@
 
 #include <apr_general.h>
 #include <apr_pools.h>
+#include <apr_file_io.h>
 
 #define SVN_DEPRECATED
 
 #include "svn_error.h"
 #include "svn_delta.h"
 #include "svn_ra.h"
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_dirent_uri.h"
 
 #include "../svn_test.h"
 #include "../svn_test_fs.h"
 #include "../../libsvn_ra_local/ra_local.h"
 
+static const char tunnel_repos_name[] = "test-repo-tunnel";
+
 /*-------------------------------------------------------------------*/
 
 /** Helper routines. **/
@@ -58,7 +64,7 @@ make_and_open_local_repos(svn_ra_session
 
   SVN_ERR(svn_uri_get_file_url_from_dirent(&url, repos_name, pool));
 
-  SVN_ERR(svn_ra_open3(session, url, NULL, cbtable, NULL, NULL, pool));
+  SVN_ERR(svn_ra_open4(session, NULL, url, NULL, cbtable, NULL, NULL, pool));
 
   return SVN_NO_ERROR;
 }
@@ -88,6 +94,91 @@ commit_changes(svn_ra_session_t *session
   return SVN_NO_ERROR;
 }
 
+static svn_boolean_t last_tunnel_check;
+static int tunnel_open_count;
+static void *check_tunnel_baton;
+static void *open_tunnel_context;
+
+static svn_boolean_t
+check_tunnel(void *tunnel_baton, const char *tunnel_name)
+{
+  if (tunnel_baton != check_tunnel_baton)
+    abort();
+  last_tunnel_check = (0 == strcmp(tunnel_name, "test"));
+  return last_tunnel_check;
+}
+
+static svn_error_t *
+open_tunnel(apr_file_t **request, apr_file_t **response,
+            void **tunnel_context, void *tunnel_baton,
+            const char *tunnel_name, const char *user,
+            const char *hostname, int port,
+            apr_pool_t *pool)
+{
+  svn_node_kind_t kind;
+  apr_proc_t *proc;
+  apr_procattr_t *attr;
+  apr_status_t status;
+  const char *args[] = { "svnserve", "-t", "-r", ".", NULL };
+  const char *svnserve;
+
+  SVN_TEST_ASSERT(tunnel_baton == check_tunnel_baton);
+
+  SVN_ERR(svn_dirent_get_absolute(&svnserve, "../../svnserve/svnserve", pool));
+#ifdef WIN32
+  svnserve = apr_pstrcat(pool, svnserve, ".exe", NULL);
+#endif
+  SVN_ERR(svn_io_check_path(svnserve, &kind, pool));
+  if (kind != svn_node_file)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                             "Could not find svnserve at %s",
+                             svn_dirent_local_style(svnserve, pool));
+
+  status = apr_procattr_create(&attr, pool);
+  if (status == APR_SUCCESS)
+    status = apr_procattr_io_set(attr, 1, 1, 0);
+  if (status == APR_SUCCESS)
+    status = apr_procattr_cmdtype_set(attr, APR_PROGRAM);
+  proc = apr_palloc(pool, sizeof(*proc));
+  if (status == APR_SUCCESS)
+    status = apr_proc_create(proc,
+                             svn_dirent_local_style(svnserve, pool),
+                             args, NULL, attr, pool);
+  if (status != APR_SUCCESS)
+    return svn_error_wrap_apr(status, "Could not run svnserve");
+#ifdef WIN32
+  apr_pool_note_subprocess(pool, proc, APR_KILL_NEVER);
+#else
+  apr_pool_note_subprocess(pool, proc, APR_KILL_ONLY_ONCE);
+#endif
+
+  /* APR pipe objects inherit by default.  But we don't want the
+   * tunnel agent's pipes held open by future child processes
+   * (such as other ra_svn sessions), so turn that off. */
+  apr_file_inherit_unset(proc->in);
+  apr_file_inherit_unset(proc->out);
+
+  *request = proc->in;
+  *response = proc->out;
+  open_tunnel_context = *tunnel_context = &kind;
+  ++tunnel_open_count;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_tunnel(void *tunnel_context, void *tunnel_baton,
+             const char *tunnel_name, const char *user,
+             const char *hostname, int port)
+{
+  SVN_TEST_ASSERT(tunnel_context == open_tunnel_context);
+  SVN_TEST_ASSERT(tunnel_baton == check_tunnel_baton);
+  --tunnel_open_count;
+  return SVN_NO_ERROR;
+}
+
+
+
+
 /*-------------------------------------------------------------------*/
 
 /** The tests **/
@@ -151,6 +242,87 @@ location_segments_test(const svn_test_op
 }
 
 
+/* Test ra_svn tunnel callbacks. */
+
+static svn_error_t *
+check_tunnel_callback_test(const svn_test_opts_t *opts,
+                           apr_pool_t *pool)
+{
+  svn_ra_callbacks2_t *cbtable;
+  svn_ra_session_t *session;
+  svn_error_t *err;
+
+  SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
+  cbtable->check_tunnel_func = check_tunnel;
+  cbtable->open_tunnel_func = open_tunnel;
+  cbtable->close_tunnel_func = close_tunnel;
+  cbtable->tunnel_baton = check_tunnel_baton = &cbtable;
+  SVN_ERR(svn_cmdline_create_auth_baton(&cbtable->auth_baton,
+                                        TRUE  /* non_interactive */,
+                                        "jrandom", "rayjandom",
+                                        NULL,
+                                        TRUE  /* no_auth_cache */,
+                                        FALSE /* trust_server_cert */,
+                                        NULL, NULL, NULL, pool));
+
+  last_tunnel_check = TRUE;
+  open_tunnel_context = NULL;
+  err = svn_ra_open4(&session, NULL, "svn+foo://localhost/no-repo",
+                     NULL, cbtable, NULL, NULL, pool);
+  svn_error_clear(err);
+  SVN_TEST_ASSERT(err);
+  SVN_TEST_ASSERT(!last_tunnel_check);
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+tunel_callback_test(const svn_test_opts_t *opts,
+                    apr_pool_t *pool)
+{
+  apr_pool_t *connection_pool;
+  svn_repos_t *repos;
+  const char *url;
+  svn_ra_callbacks2_t *cbtable;
+  svn_ra_session_t *session;
+  svn_error_t *err;
+
+  SVN_ERR(svn_test__create_repos(&repos, tunnel_repos_name, opts, pool));
+
+  url = apr_pstrcat(pool, "svn+test://localhost/", tunnel_repos_name, NULL);
+  SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
+  cbtable->check_tunnel_func = check_tunnel;
+  cbtable->open_tunnel_func = open_tunnel;
+  cbtable->close_tunnel_func = close_tunnel;
+  cbtable->tunnel_baton = check_tunnel_baton = &cbtable;
+  SVN_ERR(svn_cmdline_create_auth_baton(&cbtable->auth_baton,
+                                        TRUE  /* non_interactive */,
+                                        "jrandom", "rayjandom",
+                                        NULL,
+                                        TRUE  /* no_auth_cache */,
+                                        FALSE /* trust_server_cert */,
+                                        NULL, NULL, NULL, pool));
+
+  last_tunnel_check = FALSE;
+  open_tunnel_context = NULL;
+  tunnel_open_count = 0;
+  connection_pool = svn_pool_create(pool);
+  err = svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
+                     connection_pool);
+  if (err && err->apr_err == SVN_ERR_TEST_FAILED)
+    {
+      svn_handle_error2(err, stderr, FALSE, "svn_tests: ");
+      svn_error_clear(err);
+      return SVN_NO_ERROR;
+    }
+  SVN_ERR(err);
+  SVN_TEST_ASSERT(last_tunnel_check);
+  SVN_TEST_ASSERT(tunnel_open_count > 0);
+  svn_pool_destroy(connection_pool);
+  SVN_TEST_ASSERT(tunnel_open_count == 0);
+  return SVN_NO_ERROR;
+}
+
+
 
 /* The test table.  */
 struct svn_test_descriptor_t test_funcs[] =
@@ -158,5 +330,9 @@ struct svn_test_descriptor_t test_funcs[
     SVN_TEST_NULL,
     SVN_TEST_OPTS_PASS(location_segments_test,
                        "test svn_ra_get_location_segments"),
+    SVN_TEST_OPTS_PASS(check_tunnel_callback_test,
+                       "test ra_svn tunnel callback check"),
+    SVN_TEST_OPTS_PASS(tunel_callback_test,
+                       "test ra_svn tunnel creation callbacks"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_subr/dirent_uri-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_subr/dirent_uri-test.c Tue Oct 15 23:44:41 2013
@@ -911,6 +911,9 @@ static const testcase_canonicalize_t uri
     { "file:///C:/temp/REPOS", "file:///C:/temp/REPOS" },
     { "file:///c:/",           "file:///c:" },
 #endif /* SVN_USE_DOS_PATHS */
+    /* Hostnames that look like non-canonical paths */
+    { "file://./foo",             "file://./foo" },
+    { "http://./foo",             "http://./foo" },
   /* svn_uri_is_canonical() was a private function in the 1.6 API, and
      has since taken a MAJOR change of direction, namely that only
      absolute URLs are considered canonical uris now. */

Propchange: subversion/branches/log-addressing/subversion/tests/libsvn_subr/packed-data-test.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/tests/libsvn_subr/prefix-string-test.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/log-addressing/subversion/tests/libsvn_subr/priority-queue-test.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_subr/stream-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_subr/stream-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_subr/stream-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_subr/stream-test.c Tue Oct 15 23:44:41 2013
@@ -727,6 +727,50 @@ test_stream_base64_2(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_stringbuf_from_stream(apr_pool_t *pool)
+{
+  const char *test_cases[] =
+    {
+      "",
+      "x",
+      "this string is longer than the default 64 minimum block size used"
+      "by the function under test",
+      NULL
+    };
+
+  const char **test_case;
+  for (test_case = test_cases; *test_case; ++test_case)
+    {
+      svn_stringbuf_t *result1, *result2, *result3, *result4;
+      svn_stringbuf_t *original = svn_stringbuf_create(*test_case, pool);
+
+      svn_stream_t *stream1 = svn_stream_from_stringbuf(original, pool);
+      svn_stream_t *stream2 = svn_stream_from_stringbuf(original, pool);
+
+      SVN_ERR(svn_stringbuf_from_stream(&result1, stream1, 0, pool));
+      SVN_ERR(svn_stringbuf_from_stream(&result2, stream1, 0, pool));
+      SVN_ERR(svn_stringbuf_from_stream(&result3, stream2, original->len,
+                                        pool));
+      SVN_ERR(svn_stringbuf_from_stream(&result4, stream2, original->len,
+                                        pool));
+
+      /* C-string contents must match */
+      SVN_TEST_STRING_ASSERT(result1->data, original->data);
+      SVN_TEST_STRING_ASSERT(result2->data, "");
+      SVN_TEST_STRING_ASSERT(result3->data, original->data);
+      SVN_TEST_STRING_ASSERT(result4->data, "");
+
+      /* assumed length must match */
+      SVN_TEST_ASSERT(result1->len == original->len);
+      SVN_TEST_ASSERT(result2->len == 0);
+      SVN_TEST_ASSERT(result3->len == original->len);
+      SVN_TEST_ASSERT(result4->len == 0);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* The test table.  */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -752,5 +796,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test base64 encoding/decoding streams"),
     SVN_TEST_PASS2(test_stream_base64_2,
                    "base64 decoding allocation problem"),
+    SVN_TEST_PASS2(test_stringbuf_from_stream,
+                   "test svn_stringbuf_from_stream"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_subr/string-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_subr/string-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_subr/string-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_subr/string-test.c Tue Oct 15 23:44:41 2013
@@ -656,7 +656,7 @@ test_string_similarity(apr_pool_t *pool)
     const char *stra;
     const char *strb;
     apr_size_t lcs;
-    int score;
+    unsigned int score;
   } tests[] =
       {
 #define SCORE(lcs, len) ((2000 * (lcs) + (len)/2) / (len))

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_wc/op-depth-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_wc/op-depth-test.c Tue Oct 15 23:44:41 2013
@@ -8207,6 +8207,391 @@ move_update_parent_replace(const svn_tes
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+copy_mixed_rev_mods(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "copy_mixed_rev_mods", opts,
+                                   pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_update(&b, "", 1));
+  SVN_ERR(sbox_wc_update(&b, "A/B", 2));
+  SVN_ERR(sbox_wc_delete(&b, "A/B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+
+  {
+    nodes_row_t nodes[] = {
+      {0, "",      "normal",       1, ""},
+      {0, "A",     "normal",       1, "A"},
+      {0, "A/B",   "normal",       2, "A/B"},
+      {0, "A/B/C", "normal",       2, "A/B/C"},
+      {2, "A/B",   "normal",       NO_COPY_FROM},
+      {2, "A/B/C", "base-deleted", NO_COPY_FROM},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(sbox_wc_copy(&b, "A", "X"));
+  {
+    nodes_row_t nodes[] = {
+      {1, "X",   "normal",      1, "A"},
+      {1, "X/B", "not-present", 2, "A/B"},
+      {2, "X/B", "normal",      NO_COPY_FROM},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "X", nodes));
+  }
+
+  SVN_ERR(sbox_wc_commit(&b, "X"));
+  {
+    nodes_row_t nodes[] = {
+      {0, "X",   "normal", 3, "X"},
+      {0, "X/B", "normal", 3, "X/B"},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "X", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+move_child_to_parent_revert(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "move_child_to_parent_revert", opts,
+                                   pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+
+
+  SVN_ERR(sbox_wc_move(&b, "A/B", "B"));
+  SVN_ERR(sbox_wc_delete(&b, "A"));
+
+  /* Verify that the move is still recorded correctly */
+  {
+    nodes_row_t nodes[] = {
+      {0, "",    "normal", 0, ""},
+      {0, "A",   "normal", 1, "A"},
+      {0, "A/B", "normal", 1, "A/B"},
+
+      {1, "A",   "base-deleted", NO_COPY_FROM},
+      {1, "A/B", "base-deleted", NO_COPY_FROM, "B"},
+
+      {1, "B", "normal", 1, "A/B", MOVED_HERE},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(sbox_wc_revert(&b, "A", svn_depth_infinity));
+
+  /* Verify that the move is now just a copy */
+  {
+    nodes_row_t nodes[] = {
+      {0, "",    "normal", 0, ""},
+      {0, "A",   "normal", 1, "A"},
+      {0, "A/B", "normal", 1, "A/B"},
+
+      {1, "B", "normal", 1, "A/B"},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+move_delete_intermediate(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "move_delete_intermediate", opts,
+                                   pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A/A/A"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_1"));
+
+  SVN_ERR(sbox_wc_delete(&b, "A"));
+  SVN_ERR(sbox_wc_move(&b, "B", "A"));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_2"));
+
+  SVN_ERR(sbox_wc_delete(&b, "A/A"));
+  SVN_ERR(sbox_wc_move(&b, "C/A", "A/A"));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_3"));
+
+  /* Verify that the move is still recorded correctly */
+  {
+    nodes_row_t nodes[] = {
+
+      {0, "",           "normal",       0, ""},
+
+      {1, "AAA_1",      "normal",       1, "A/A/A",             MOVED_HERE},
+      {1, "AAA_1/A",    "normal",       1, "A/A/A/A",           MOVED_HERE},
+      {1, "AAA_2",      "normal",       1, "B/A/A",             MOVED_HERE},
+      {1, "AAA_2/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+      {1, "AAA_3",      "normal",       1, "C/A/A",             MOVED_HERE},
+      {1, "AAA_3/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {0, "A",          "normal",       1, "A"},
+      {0, "A/A",        "normal",       1, "A/A"},
+      {0, "A/A/A",      "normal",       1, "A/A/A"},
+      {0, "A/A/A/A",    "normal",       1, "A/A/A/A"},
+
+      {1, "A",          "normal",       1, "B",                 MOVED_HERE},
+      {1, "A/A",        "normal",       1, "B/A",               MOVED_HERE},
+      {1, "A/A/A",      "normal",       1, "B/A/A", FALSE, "AAA_1",   TRUE},
+      {1, "A/A/A/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+
+      {2, "A/A",        "normal",       1, "C/A", MOVED_HERE},
+      {2, "A/A/A",      "normal",       1, "C/A/A", FALSE, "AAA_2",   TRUE},
+      {2, "A/A/A/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {3, "A/A/A",      "base-deleted", NO_COPY_FROM,      "AAA_3"},
+      {3, "A/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "B",          "normal",       1, "B"},
+      {0, "B/A",        "normal",       1, "B/A"},
+      {0, "B/A/A",      "normal",       1, "B/A/A"},
+      {0, "B/A/A/A",    "normal",       1, "B/A/A/A"},
+
+      {1, "B",          "base-deleted", NO_COPY_FROM, "A"},
+      {1, "B/A",        "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A",      "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "C",          "normal",       1, "C"},
+      {0, "C/A",        "normal",       1, "C/A"},
+      {0, "C/A/A",      "normal",       1, "C/A/A"},
+      {0, "C/A/A/A",    "normal",       1, "C/A/A/A"},
+
+      {2, "C/A",        "base-deleted", NO_COPY_FROM, "A/A"},
+      {2, "C/A/A",      "base-deleted", NO_COPY_FROM},
+      {2, "C/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0},
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  /* Ok, now we are in the very ugly case where A/A/A is moved away 3 times */
+
+  /* Let's delete A */
+  SVN_ERR(sbox_wc_delete(&b, "A"));
+
+  /* AAA_1 should now be a copy, but AAA_2 and AAA_3 should still be moves,
+     but now from the original location instead of from "A/A/A" */
+  {
+    nodes_row_t nodes[] = {
+
+      {0, "",           "normal",       0, ""},
+
+      {1, "AAA_1",      "normal",       1, "A/A/A",},
+      {1, "AAA_1/A",    "normal",       1, "A/A/A/A"},
+      {1, "AAA_2",      "normal",       1, "B/A/A",             MOVED_HERE},
+      {1, "AAA_2/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+      {1, "AAA_3",      "normal",       1, "C/A/A",             MOVED_HERE},
+      {1, "AAA_3/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {0, "A",          "normal",       1, "A"},
+      {0, "A/A",        "normal",       1, "A/A"},
+      {0, "A/A/A",      "normal",       1, "A/A/A"},
+      {0, "A/A/A/A",    "normal",       1, "A/A/A/A"},
+
+      {0, "B",          "normal",       1, "B"},
+      {0, "B/A",        "normal",       1, "B/A"},
+      {0, "B/A/A",      "normal",       1, "B/A/A"},
+      {0, "B/A/A/A",    "normal",       1, "B/A/A/A"},
+
+      {1, "B",          "base-deleted", NO_COPY_FROM},
+      {1, "B/A",        "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A",      "base-deleted", NO_COPY_FROM, "AAA_2"},
+      {1, "B/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "C",          "normal",       1, "C"},
+      {0, "C/A",        "normal",       1, "C/A"},
+      {0, "C/A/A",      "normal",       1, "C/A/A"},
+      {0, "C/A/A/A",    "normal",       1, "C/A/A/A"},
+
+      {2, "C/A",        "base-deleted", NO_COPY_FROM},
+      {2, "C/A/A",      "base-deleted", NO_COPY_FROM, "AAA_3"},
+      {2, "C/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0},
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+move_revert_intermediate(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "move_revert_intermediate", opts,
+                                   pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "B/A/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A/A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "C/A/A/A"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_1"));
+
+  SVN_ERR(sbox_wc_delete(&b, "A"));
+  SVN_ERR(sbox_wc_move(&b, "B", "A"));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_2"));
+
+  SVN_ERR(sbox_wc_delete(&b, "A/A"));
+  SVN_ERR(sbox_wc_move(&b, "C/A", "A/A"));
+
+  SVN_ERR(sbox_wc_move(&b, "A/A/A", "AAA_3"));
+
+  /* Verify that the move is still recorded correctly */
+  {
+    nodes_row_t nodes[] = {
+
+      {0, "",           "normal",       0, ""},
+
+      {1, "AAA_1",      "normal",       1, "A/A/A",             MOVED_HERE},
+      {1, "AAA_1/A",    "normal",       1, "A/A/A/A",           MOVED_HERE},
+      {1, "AAA_2",      "normal",       1, "B/A/A",             MOVED_HERE},
+      {1, "AAA_2/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+      {1, "AAA_3",      "normal",       1, "C/A/A",             MOVED_HERE},
+      {1, "AAA_3/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {0, "A",          "normal",       1, "A"},
+      {0, "A/A",        "normal",       1, "A/A"},
+      {0, "A/A/A",      "normal",       1, "A/A/A"},
+      {0, "A/A/A/A",    "normal",       1, "A/A/A/A"},
+
+      {1, "A",          "normal",       1, "B",                 MOVED_HERE},
+      {1, "A/A",        "normal",       1, "B/A",               MOVED_HERE},
+      {1, "A/A/A",      "normal",       1, "B/A/A", FALSE, "AAA_1",   TRUE},
+      {1, "A/A/A/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+
+      {2, "A/A",        "normal",       1, "C/A", MOVED_HERE},
+      {2, "A/A/A",      "normal",       1, "C/A/A", FALSE, "AAA_2",   TRUE},
+      {2, "A/A/A/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {3, "A/A/A",      "base-deleted", NO_COPY_FROM,      "AAA_3"},
+      {3, "A/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "B",          "normal",       1, "B"},
+      {0, "B/A",        "normal",       1, "B/A"},
+      {0, "B/A/A",      "normal",       1, "B/A/A"},
+      {0, "B/A/A/A",    "normal",       1, "B/A/A/A"},
+
+      {1, "B",          "base-deleted", NO_COPY_FROM, "A"},
+      {1, "B/A",        "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A",      "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "C",          "normal",       1, "C"},
+      {0, "C/A",        "normal",       1, "C/A"},
+      {0, "C/A/A",      "normal",       1, "C/A/A"},
+      {0, "C/A/A/A",    "normal",       1, "C/A/A/A"},
+
+      {2, "C/A",        "base-deleted", NO_COPY_FROM, "A/A"},
+      {2, "C/A/A",      "base-deleted", NO_COPY_FROM},
+      {2, "C/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0},
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  /* Ok, now we are in the very ugly case where A/A/A is moved away 3 times */
+
+  /* Let's revert A */
+  SVN_ERR(sbox_wc_revert(&b, "A", svn_depth_infinity));
+
+  /* AAA_1 should now be a copy, but AAA_2 and AAA_3 should still be moves,
+     but now from the original location instead of from "A/A/A" */
+  {
+    nodes_row_t nodes[] = {
+
+      {0, "",           "normal",       0, ""},
+
+      {1, "AAA_1",      "normal",       1, "A/A/A",},
+      {1, "AAA_1/A",    "normal",       1, "A/A/A/A"},
+      {1, "AAA_2",      "normal",       1, "B/A/A",             MOVED_HERE},
+      {1, "AAA_2/A",    "normal",       1, "B/A/A/A",           MOVED_HERE},
+      {1, "AAA_3",      "normal",       1, "C/A/A",             MOVED_HERE},
+      {1, "AAA_3/A",    "normal",       1, "C/A/A/A",           MOVED_HERE},
+
+      {0, "A",          "normal",       1, "A"},
+      {0, "A/A",        "normal",       1, "A/A"},
+      {0, "A/A/A",      "normal",       1, "A/A/A"},
+      {0, "A/A/A/A",    "normal",       1, "A/A/A/A"},
+
+      {0, "B",          "normal",       1, "B"},
+      {0, "B/A",        "normal",       1, "B/A"},
+      {0, "B/A/A",      "normal",       1, "B/A/A"},
+      {0, "B/A/A/A",    "normal",       1, "B/A/A/A"},
+
+      {1, "B",          "base-deleted", NO_COPY_FROM},
+      {1, "B/A",        "base-deleted", NO_COPY_FROM},
+      {1, "B/A/A",      "base-deleted", NO_COPY_FROM, "AAA_2"},
+      {1, "B/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0, "C",          "normal",       1, "C"},
+      {0, "C/A",        "normal",       1, "C/A"},
+      {0, "C/A/A",      "normal",       1, "C/A/A"},
+      {0, "C/A/A/A",    "normal",       1, "C/A/A/A"},
+
+      {2, "C/A",        "base-deleted", NO_COPY_FROM},
+      {2, "C/A/A",      "base-deleted", NO_COPY_FROM, "AAA_3"},
+      {2, "C/A/A/A",    "base-deleted", NO_COPY_FROM},
+
+      {0},
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
 
@@ -8362,5 +8747,13 @@ struct svn_test_descriptor_t test_funcs[
                        "update with tree conflict (issue 4347)"),
     SVN_TEST_OPTS_PASS(move_update_parent_replace,
                        "move update with replaced parent (issue 4388)"),
+    SVN_TEST_OPTS_XFAIL(copy_mixed_rev_mods,
+                       "copy mixed-rev with mods"),
+    SVN_TEST_OPTS_PASS(move_child_to_parent_revert,
+                       "move child to parent and revert (issue 4436)"),
+    SVN_TEST_OPTS_XFAIL(move_delete_intermediate,
+                       "move more than once, delete intermediate"),
+    SVN_TEST_OPTS_XFAIL(move_revert_intermediate,
+                       "move more than once, revert intermediate"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/log-addressing/subversion/tests/libsvn_wc/wc-queries-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/tests/libsvn_wc/wc-queries-test.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/tests/libsvn_wc/wc-queries-test.c (original)
+++ subversion/branches/log-addressing/subversion/tests/libsvn_wc/wc-queries-test.c Tue Oct 15 23:44:41 2013
@@ -165,7 +165,7 @@ test_sqlite_version(apr_pool_t *scratch_
   printf("DBG: Using Sqlite %s\n", sqlite3_version);
 
   if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER)
-    printf("DBG: Compiled against Sqlite %s", SQLITE_VERSION);
+    printf("DBG: Compiled against Sqlite %s\n", SQLITE_VERSION);
 
   if (sqlite3_libversion_number() < SQLITE_VERSION_NUMBER)
     return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,

Modified: subversion/branches/log-addressing/tools/client-side/svn-bench/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/tools/client-side/svn-bench/cl.h?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/tools/client-side/svn-bench/cl.h (original)
+++ subversion/branches/log-addressing/tools/client-side/svn-bench/cl.h Tue Oct 15 23:44:41 2013
@@ -90,6 +90,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t no_revprops;     /* retrieve no revprops */
   apr_hash_t *revprop_table;     /* table of revision properties to get/set */
   svn_boolean_t use_merge_history; /* use/display extra merge information */
+  svn_boolean_t auto_moves;      /* interpret unique DEL/ADD pairs as moves */
   svn_boolean_t trust_server_cert; /* trust server SSL certs that would
                                       otherwise be rejected as "untrusted" */
 } svn_cl__opt_state_t;
@@ -107,7 +108,8 @@ svn_opt_subcommand_t
   svn_cl__help,
   svn_cl__null_export,
   svn_cl__null_list,
-  svn_cl__null_log;
+  svn_cl__null_log,
+  svn_cl__null_info;
 
 
 /* See definition in main.c for documentation. */

Modified: subversion/branches/log-addressing/tools/client-side/svn-bench/null-log-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/tools/client-side/svn-bench/null-log-cmd.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/tools/client-side/svn-bench/null-log-cmd.c (original)
+++ subversion/branches/log-addressing/tools/client-side/svn-bench/null-log-cmd.c Tue Oct 15 23:44:41 2013
@@ -140,6 +140,9 @@ svn_cl__null_log(apr_getopt_t *os,
   apr_array_header_t *revprops;
   svn_opt_revision_t target_peg_revision;
   const char *target_path_or_url;
+  svn_move_behavior_t move_behavior = opt_state->auto_moves
+                                    ? svn_move_behavior_auto_moves
+                                    : svn_move_behavior_explicit_moves;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -202,13 +205,14 @@ svn_cl__null_log(apr_getopt_t *os,
   APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
   if (!opt_state->quiet)
     APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
-  SVN_ERR(svn_client_log5(targets,
+  SVN_ERR(svn_client_log6(targets,
                           &target_peg_revision,
                           opt_state->revision_ranges,
                           opt_state->limit,
                           opt_state->verbose,
                           opt_state->stop_on_copy,
                           opt_state->use_merge_history,
+                          move_behavior,
                           revprops,
                           log_entry_receiver,
                           &lb,

Modified: subversion/branches/log-addressing/tools/client-side/svn-bench/svn-bench.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/tools/client-side/svn-bench/svn-bench.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/tools/client-side/svn-bench/svn-bench.c (original)
+++ subversion/branches/log-addressing/tools/client-side/svn-bench/svn-bench.c Tue Oct 15 23:44:41 2013
@@ -66,7 +66,9 @@ typedef enum svn_cl__longopt_t {
   opt_with_revprop,
   opt_with_all_revprops,
   opt_with_no_revprops,
-  opt_trust_server_cert
+  opt_auto_moves,
+  opt_trust_server_cert,
+  opt_changelist
 } svn_cl__longopt_t;
 
 
@@ -147,6 +149,10 @@ const apr_getopt_option_t svn_cl__option
                     N_("set revision property ARG in new revision\n"
                        "                             "
                        "using the name[=value] format")},
+  {"auto-moves",    opt_auto_moves, 0,
+                    N_("attempt to interpret matching unique DEL+ADD\n"
+                       "                             "
+                       "pairs as moves")},
   {"use-merge-history", 'g', 0,
                     N_("use/display additional information from merge\n"
                        "                             "
@@ -255,10 +261,20 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  behavior, which can be useful for determining branchpoints.\n"),
     {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy,
      'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop,
-     'x',},
+     opt_auto_moves, 'x',},
     {{opt_with_revprop, N_("retrieve revision property ARG")},
      {'c', N_("the change made in revision ARG")}} },
 
+  { "null-info", svn_cl__null_info, {0}, N_
+    ("Display information about a local or remote item.\n"
+     "usage: info [TARGET[@REV]...]\n"
+     "\n"
+     "  Print information about each TARGET (default: '.').\n"
+     "  TARGET may be either a working-copy path or URL.  If specified, REV\n"
+     "  determines in which revision the target is first looked up.\n"),
+    {'r', 'R', opt_depth, opt_targets, opt_changelist}
+  },
+
   { NULL, NULL, {0}, NULL, {0} }
 };
 
@@ -534,6 +550,9 @@ sub_main(int argc, const char *argv[], a
                                                 TRUE, pool);
         }
         break;
+      case 'R':
+        opt_state.depth = svn_depth_infinity;
+        break;
       case 'N':
         descend = FALSE;
         break;
@@ -618,6 +637,9 @@ sub_main(int argc, const char *argv[], a
       case 'g':
         opt_state.use_merge_history = TRUE;
         break;
+      case opt_auto_moves:
+        opt_state.auto_moves = TRUE;
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */

Modified: subversion/branches/log-addressing/tools/dev/fsfs-access-map.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/tools/dev/fsfs-access-map.c?rev=1532597&r1=1532596&r2=1532597&view=diff
==============================================================================
--- subversion/branches/log-addressing/tools/dev/fsfs-access-map.c (original)
+++ subversion/branches/log-addressing/tools/dev/fsfs-access-map.c Tue Oct 15 23:44:41 2013
@@ -52,9 +52,15 @@ typedef struct file_stats_t
   /* number of lseek calls to clusters not previously read */
   apr_int64_t uncached_seek_count;
 
+  /* number of lseek counts not followed by a read */
+  apr_int64_t unnecessary_seeks;
+
   /* number of read() calls */
   apr_int64_t read_count;
 
+  /* number of read() calls that returned 0 bytes */
+  apr_int64_t empty_reads;
+  
   /* total number of bytes returned by those reads */
   apr_int64_t read_size;
 
@@ -86,6 +92,8 @@ typedef struct handle_info_t
   /* bytes read so far in the current series of reads started (default: 0) */
   apr_int64_t last_read_size;
 
+  /* number of read() calls in this series */
+  apr_int64_t read_count;
 } handle_info_t;
 
 /* useful typedef */
@@ -139,6 +147,11 @@ store_read_info(handle_info_t *handle_in
             ++*count;
         }
     }
+  else if (handle_info->read_count == 0)
+    {
+      /* two consecutive seeks */
+      handle_info->file->unnecessary_seeks++;
+    }
 }
 
 /* Handle a open() call.  Ensures that a file_info_t for the given NAME
@@ -231,9 +244,13 @@ read_file(int handle, apr_int64_t count)
     {
       /* known file handle -> expand current read sequence */
 
+      handle_info->read_count++;
       handle_info->last_read_size += count;
       handle_info->file->read_count++;
       handle_info->file->read_size += count;
+
+      if (count == 0)
+        handle_info->file->empty_reads++;
     }
 }
 
@@ -253,6 +270,7 @@ seek_file(int handle, apr_int64_t locati
 
       handle_info->last_read_size = 0;
       handle_info->last_read_start = location;
+      handle_info->read_count = 0;
       handle_info->file->seek_count++;
 
       /* if we seek to a location that had not been read from before,
@@ -678,6 +696,8 @@ print_stats(apr_pool_t *pool)
   apr_int64_t clusters_read = 0;
   apr_int64_t unique_clusters_read = 0;
   apr_int64_t uncached_seek_count = 0;
+  apr_int64_t unnecessary_seek_count = 0;
+  apr_int64_t empty_read_count = 0;
 
   apr_hash_index_t *hi;
   for (hi = apr_hash_first(pool, files); hi; hi = apr_hash_next(hi))
@@ -695,13 +715,17 @@ print_stats(apr_pool_t *pool)
       clusters_read += file->clusters_read;
       unique_clusters_read += file->unique_clusters_read;
       uncached_seek_count += file->uncached_seek_count;
+      unnecessary_seek_count += file->unnecessary_seeks;
+      empty_read_count += file->empty_reads;
     }
 
   printf("%20s files\n", svn__i64toa_sep(apr_hash_count(files), ',', pool));
   printf("%20s files opened\n", svn__i64toa_sep(open_count, ',', pool));
   printf("%20s seeks\n", svn__i64toa_sep(seek_count, ',', pool));
+  printf("%20s unnecessary seeks\n", svn__i64toa_sep(unnecessary_seek_count, ',', pool));
   printf("%20s uncached seeks\n", svn__i64toa_sep(uncached_seek_count, ',', pool));
   printf("%20s reads\n", svn__i64toa_sep(read_count, ',', pool));
+  printf("%20s empty reads\n", svn__i64toa_sep(empty_read_count, ',', pool));
   printf("%20s unique clusters read\n", svn__i64toa_sep(unique_clusters_read, ',', pool));
   printf("%20s clusters read\n", svn__i64toa_sep(clusters_read, ',', pool));
   printf("%20s bytes read\n", svn__i64toa_sep(read_size, ',', pool));
@@ -767,4 +791,4 @@ int main(int argc, const char *argv[])
   apr_file_close(file);
 
   return 0;
-}
\ No newline at end of file
+}