You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gb...@apache.org on 2013/10/13 18:11:00 UTC

svn commit: r1531702 [4/4] - in /subversion/branches/invoke-diff-cmd-feature: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/i...

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svnserve/svnserve.c?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/svnserve/svnserve.c Sun Oct 13 16:10:59 2013
@@ -55,6 +55,7 @@
 #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
@@ -77,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. */
@@ -350,14 +352,6 @@ static const apr_getopt_option_t svnserv
     {0,                  0,   0, 0}
   };
 
-/* unused connection pools.
- * Use CONNECTION_POOLS_MUTEX to serialize access to this collection.
- */
-apr_array_header_t *connection_pools = NULL;
-
-/* Mutex to serialize access to connection_pools */
-svn_mutex__t *connection_pools_mutex = NULL;
-
 static void usage(const char *progname, apr_pool_t *pool)
 {
   if (!progname)
@@ -451,74 +445,6 @@ static apr_status_t redirect_stdout(void
   return apr_file_dup2(out_file, err_file, pool);
 }
 
-/* Create the global collection object for unused connection pools plus
- * the necessary mutex.  Their lifetime will be bound to POOL.
- */
-static svn_error_t *
-initialize_connection_pools(apr_pool_t *pool)
-{
-  SVN_ERR(svn_mutex__init(&connection_pools_mutex, TRUE, pool));
-  connection_pools = apr_array_make(pool, 16, sizeof(apr_pool_t *));
-
-  return SVN_NO_ERROR;
-}
-
-/* Return a currently unused connection pool in *POOL. If no such pool
- * exists, create a new root pool and return that in *POOL.
- */
-static svn_error_t *
-acquire_connection_pool_internal(apr_pool_t **pool)
-{
-  SVN_ERR(svn_mutex__lock(connection_pools_mutex));
-  *pool = connection_pools->nelts
-        ? *(apr_pool_t **)apr_array_pop(connection_pools)
-        : apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-  SVN_ERR(svn_mutex__unlock(connection_pools_mutex, SVN_NO_ERROR));
-    
-  return SVN_NO_ERROR;
-}
-
-/* Return a currently unused connection pool. If no such pool exists,
- * create a new root pool and return that.
- */
-static apr_pool_t *
-acquire_connection_pool(void)
-{
-  apr_pool_t *pool;
-  svn_error_t *err = acquire_connection_pool_internal(&pool);
-  if (err)
-    {
-      /* Mutex failure?!  Well, try to continue with unrecycled data. */
-      svn_error_clear(err);
-      pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-    }
-
-  return pool;
-}
-
-/* Clear and release the given connection POOL.
- */
-static void
-release_connection_pool(apr_pool_t *pool)
-{
-  svn_error_t *err;
-
-  svn_pool_clear(pool);
-
-  err = svn_mutex__lock(connection_pools_mutex);
-  if (err)
-    {
-      svn_error_clear(err);
-      svn_pool_destroy(pool);
-    }
-  else
-    {
-      APR_ARRAY_PUSH(connection_pools, apr_pool_t *) = pool;
-      svn_error_clear(svn_mutex__unlock(connection_pools_mutex,
-                                        SVN_NO_ERROR));
-    }
-}
-
 #if APR_HAS_THREADS
 /* The pool passed to apr_thread_create can only be released when both
 
@@ -528,17 +454,20 @@ release_connection_pool(apr_pool_t *pool
    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;
@@ -548,7 +477,7 @@ static void
 release_shared_pool(struct shared_pool_t *shared)
 {
   if (svn_atomic_dec(&shared->count) == 0)
-    release_connection_pool(shared->pool);
+    svn_root_pools__release_pool(shared->pool, shared->root_pools);
 }
 #endif
 
@@ -588,8 +517,8 @@ serve_socket(apr_socket_t *usock,
   /* process the actual request and log errors */
   err = serve(conn, params, pool);
   if (err)
-    log_error(err, params->log_file, params->log_file_mutex,
-              svn_ra_svn_conn_remote_host(conn), NULL, NULL, pool);
+    logger__log_error(params->logger, err, NULL,
+                      get_client_info(conn, params, pool));
 
   return svn_error_trace(err);
 }
@@ -598,15 +527,25 @@ serve_socket(apr_socket_t *usock,
 struct serve_thread_t {
   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_socket(d->usock, 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;
@@ -660,7 +599,6 @@ 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;
@@ -669,7 +607,7 @@ int main(int argc, const char *argv[])
   apr_status_t status;
   apr_proc_t proc;
 #if APR_HAS_THREADS
-  struct shared_pool_t *shared_pool;
+  shared_pool_t *shared_pool;
   struct serve_thread_t *thread_data;
 #if HAVE_THREADPOOLS
   apr_thread_pool_t *threads;
@@ -694,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)
@@ -727,8 +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.log_file_mutex = NULL;
+  params.logger = NULL;
   params.vhost = FALSE;
   params.username_case = CASE_ASIS;
   params.memory_cache_size = (apr_uint64_t)-1;
@@ -984,12 +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(svn_mutex__init(&params.log_file_mutex, TRUE, pool));
-    }
+    SVN_INT_ERR(logger__create(&params.logger, log_filename, pool));
 
   if (params.tunnel_user && run_mode != run_mode_tunnel)
     {
@@ -1002,6 +935,7 @@ 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);
@@ -1212,10 +1146,18 @@ int main(int argc, const char *argv[])
     svn_cache_config_set(&settings);
   }
 
-  err = initialize_connection_pools(pool);
+  /* 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)
     {
@@ -1241,6 +1183,8 @@ int main(int argc, const char *argv[])
 
   while (1)
     {
+      apr_pool_t *socket_pool;
+
 #ifdef WIN32
       if (winservice_is_stopping())
         return ERROR_SUCCESS;
@@ -1250,21 +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 = acquire_connection_pool();
+      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))
         {
-          release_connection_pool(connection_pool);
+          svn_root_pools__release_pool(socket_pool, socket_pools);
           continue;
         }
       if (status)
@@ -1276,7 +1220,7 @@ int main(int argc, const char *argv[])
 
       if (run_mode == run_mode_listen_once)
         {
-          err = serve_socket(usock, &params, connection_pool);
+          err = serve_socket(usock, &params, socket_pool);
 
           if (err)
             svn_handle_error2(err, stdout, FALSE, "svnserve: ");
@@ -1291,11 +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);
-              svn_error_clear(serve_socket(usock, &params, connection_pool));
+              svn_error_clear(serve_socket(usock, &params, socket_pool));
               apr_socket_close(usock);
               exit(0);
             }
@@ -1306,13 +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, params.log_file_mutex,
-                        NULL, NULL, NULL, /* ip, user, repos */
-                        connection_pool);
+              logger__log_error(params.logger, err, NULL, NULL);
               svn_error_clear(err);
               apr_socket_close(usock);
             }
-          release_connection_pool(connection_pool);
+          svn_root_pools__release_pool(socket_pool, socket_pools);
 #endif
           break;
 
@@ -1321,9 +1263,9 @@ 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);
+          shared_pool = attach_shared_pool(socket_pool, socket_pools);
 
-          thread_data = apr_palloc(connection_pool, sizeof(*thread_data));
+          thread_data = apr_palloc(socket_pool, sizeof(*thread_data));
           thread_data->usock = usock;
           thread_data->params = &params;
           thread_data->shared_pool = shared_pool;
@@ -1331,7 +1273,7 @@ int main(int argc, const char *argv[])
           status = apr_thread_pool_push(threads, serve_thread, thread_data,
                                         0, NULL);
 #else
-          status = apr_threadattr_create(&tattr, connection_pool);
+          status = apr_threadattr_create(&tattr, socket_pool);
           if (status)
             {
               err = svn_error_wrap_apr(status, _("Can't create threadattr"));
@@ -1363,8 +1305,8 @@ int main(int argc, const char *argv[])
 
         case connection_mode_single:
           /* Serve one connection at a time. */
-          svn_error_clear(serve_socket(usock, &params, connection_pool));
-          release_connection_pool(connection_pool);
+          svn_error_clear(serve_socket(usock, &params, socket_pool));
+          svn_root_pools__release_pool(socket_pool, socket_pools);
         }
     }
 

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/move_tests.py?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/move_tests.py Sun Oct 13 16:10:59 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/invoke-diff-cmd-feature/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/revert_tests.py?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/revert_tests.py Sun Oct 13 16:10:59 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/invoke-diff-cmd-feature/subversion/tests/libsvn_ra/ra-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_ra/ra-test.c?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_ra/ra-test.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_ra/ra-test.c Sun Oct 13 16:10:59 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,75 @@ commit_changes(svn_ra_session_t *session
   return SVN_NO_ERROR;
 }
 
+static int tunnel_open_count;
+
+static svn_error_t *
+open_tunnel(apr_file_t **request, apr_file_t **response,
+            void **tunnel_baton, void *callbacks_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_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;
+  *tunnel_baton = NULL;
+  ++tunnel_open_count;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_tunnel(void *tunnel_baton, void *callbacks_baton,
+             const char *tunnel_name, const char *user,
+             const char *hostname, int port)
+{
+  --tunnel_open_count;
+  return SVN_NO_ERROR;
+}
+
+
+
+
 /*-------------------------------------------------------------------*/
 
 /** The tests **/
@@ -151,6 +226,50 @@ location_segments_test(const svn_test_op
 }
 
 
+/* Test ra_svn tunnel callbacks. */
+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->open_tunnel = open_tunnel;
+  cbtable->close_tunnel = close_tunnel;
+  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));
+
+  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(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 +277,7 @@ 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(tunel_callback_test,
+                       "test ra_svn tunnel creation callbacks"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_wc/op-depth-test.c?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/libsvn_wc/op-depth-test.c Sun Oct 13 16:10:59 2013
@@ -8262,6 +8262,195 @@ copy_mixed_rev_mods(const svn_test_opts_
   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_abspath_more_than_once(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/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},
+
+    };
+    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},
+
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
 
@@ -8419,5 +8608,9 @@ struct svn_test_descriptor_t test_funcs[
                        "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_abspath_more_than_once,
+                       "move one abspath more than once"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/invoke-diff-cmd-feature/tools/dev/fsfs-access-map.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/tools/dev/fsfs-access-map.c?rev=1531702&r1=1531701&r2=1531702&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/tools/dev/fsfs-access-map.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/tools/dev/fsfs-access-map.c Sun Oct 13 16:10:59 2013
@@ -791,4 +791,4 @@ int main(int argc, const char *argv[])
   apr_file_close(file);
 
   return 0;
-}
\ No newline at end of file
+}