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/11/27 08:53:35 UTC
svn commit: r1545955 [12/15] - in /subversion/branches/fsfs-improvements: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/server-side/ contrib/server-side/svncutter/ notes/
subversion/bindings/javahl/native/ ...
Modified: subversion/branches/fsfs-improvements/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/svnserve/svnserve.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/fsfs-improvements/subversion/svnserve/svnserve.c Wed Nov 27 07:53:29 2013
@@ -48,6 +48,7 @@
#include "svn_cache_config.h"
#include "svn_version.h"
#include "svn_io.h"
+#include "svn_hash.h"
#include "svn_private_config.h"
@@ -360,7 +361,6 @@ static void usage(const char *progname,
svn_error_clear(svn_cmdline_fprintf(stderr, pool,
_("Type '%s --help' for usage.\n"),
progname));
- exit(1);
}
static void help(apr_pool_t *pool)
@@ -393,7 +393,6 @@ static void help(apr_pool_t *pool)
svn_error_clear(svn_cmdline_fprintf(stdout, pool, " %s\n", optstr));
}
svn_error_clear(svn_cmdline_fprintf(stdout, pool, "\n"));
- exit(0);
}
static svn_error_t * version(svn_boolean_t quiet, apr_pool_t *pool)
@@ -445,113 +444,172 @@ static apr_status_t redirect_stdout(void
return apr_file_dup2(out_file, err_file, pool);
}
-#if APR_HAS_THREADS
-/* The pool passed to apr_thread_create can only be released when both
-
- A: the call to apr_thread_create has returned to the calling thread
- B: the new thread has started running and reached apr_thread_start_t
-
- 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. */
-typedef struct shared_pool_t {
- svn_atomic_t count;
- 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)
+/* Wait for the next client connection to come in from SOCK. Allocate
+ * the connection in a root pool from CONNECTION_POOLS and assign PARAMS.
+ * Return the connection object in *CONNECTION.
+ *
+ * Use HANDLING_MODE for proper internal cleanup.
+ */
+static svn_error_t *
+accept_connection(connection_t **connection,
+ apr_socket_t *sock,
+ svn_root_pools__t *connection_pools,
+ serve_params_t *params,
+ enum connection_handling_mode handling_mode)
{
- shared_pool_t *shared = apr_palloc(pool, sizeof(*shared));
-
- shared->pool = pool;
- shared->root_pools = root_pools;
- svn_atomic_set(&shared->count, 2);
+ apr_status_t status;
+
+ /* Non-standard pool handling. The main thread never blocks to join
+ * the connection threads so it cannot clean up after each one. So
+ * separate pools that can be cleared at thread exit are used. */
+
+ apr_pool_t *pool = svn_root_pools__acquire_pool(connection_pools);
+ *connection = apr_pcalloc(pool, sizeof(**connection));
+ (*connection)->pool = pool;
+ (*connection)->params = params;
+ (*connection)->root_pools = connection_pools;
+ (*connection)->ref_count = 1;
+
+ do
+ {
+ #ifdef WIN32
+ if (winservice_is_stopping())
+ exit(0);
+ #endif
+
+ status = apr_socket_accept(&(*connection)->usock, sock, pool);
+ if (handling_mode == connection_mode_fork)
+ {
+ apr_proc_t proc;
+
+ /* Collect any zombie child processes. */
+ while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT,
+ pool) == APR_CHILD_DONE)
+ ;
+ }
+ }
+ while (APR_STATUS_IS_EINTR(status)
+ || APR_STATUS_IS_ECONNABORTED(status)
+ || APR_STATUS_IS_ECONNRESET(status));
+
+ return status
+ ? svn_error_wrap_apr(status, _("Can't accept client connection"))
+ : SVN_NO_ERROR;
+}
- return shared;
+/* Add a reference to CONNECTION, i.e. keep it and it's pool valid unless
+ * that reference gets released using release_shared_pool().
+ */
+static void
+attach_connection(connection_t *connection)
+{
+ svn_atomic_inc(&connection->ref_count);
}
+/* Release a reference to CONNECTION. If there are no more references,
+ * the connection will be
+ */
static void
-release_shared_pool(struct shared_pool_t *shared)
+close_connection(connection_t *connection)
{
- if (svn_atomic_dec(&shared->count) == 0)
- svn_root_pools__release_pool(shared->pool, shared->root_pools);
+ /* this will automatically close USOCK */
+ if (svn_atomic_dec(&connection->ref_count) == 0)
+ svn_root_pools__release_pool(connection->pool, connection->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.
+ *
+ * If an error occurs, log it and also return it.
*/
static svn_error_t *
-serve_socket(apr_socket_t *usock,
- serve_params_t *params,
+serve_socket(connection_t *connection,
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);
+ svn_error_t *err = serve_interruptable(NULL, connection, NULL, pool);
if (err)
- logger__log_error(params->logger, err, NULL,
- get_client_info(conn, params, pool));
+ logger__log_error(connection->params->logger, err, NULL,
+ get_client_info(connection->conn, connection->params,
+ pool));
return svn_error_trace(err);
}
-/* "Arguments" passed from the main thread to the connection thread */
-struct serve_thread_t {
- apr_socket_t *usock;
- serve_params_t *params;
-#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;
+#if HAVE_THREADPOOLS
+
+/* The global thread pool serving all connections. */
+apr_thread_pool_t *threads;
+
+/* Very simple load determination callback for serve_interruptable:
+ With less than have the threads in THREADS in use, we can afford to
+ wait in the socket read() function. Otherwise, poll them round-robin. */
+static svn_boolean_t
+is_busy(connection_t *connection)
+{
+ return apr_thread_pool_threads_count(threads) * 2
+ > apr_thread_pool_thread_max_get(threads);
+}
+
+/* Serve the connection given by DATA. Under high load, serve only
+ the current command (if any) and then put the connection back into
+ THREAD's task pool. */
static void * APR_THREAD_FUNC serve_thread(apr_thread_t *tid, void *data)
{
- struct serve_thread_t *d = data;
+ svn_boolean_t done;
+ connection_t *connection = data;
+ svn_error_t *err;
+
+ apr_pool_t *pool = svn_root_pools__acquire_pool(connection_pools);
+
+ /* process the actual request and log errors */
+ err = serve_interruptable(&done, connection, is_busy, pool);
+ if (err)
+ {
+ logger__log_error(connection->params->logger, err, NULL,
+ get_client_info(connection->conn, connection->params,
+ pool));
+ svn_error_clear(err);
+ }
+ svn_root_pools__release_pool(pool, connection_pools);
+
+ /* Close or re-schedule connection. */
+ if (done)
+ close_connection(connection);
+ else
+ apr_thread_pool_push(threads, serve_thread, connection, 0, NULL);
+
+ return NULL;
+}
+
+#else
+/* Fully serve the connection given by DATA. */
+static void * APR_THREAD_FUNC serve_thread(apr_thread_t *tid, void *data)
+{
+ struct connection_t *connection = data;
apr_pool_t *pool = svn_root_pools__acquire_pool(connection_pools);
- svn_error_clear(serve_socket(d->usock, d->params, pool));
+
+ /* serve_socket() logs any error it returns, so ignore it. */
+ svn_error_clear(serve_socket(connection, pool));
+
svn_root_pools__release_pool(pool, connection_pools);
- release_shared_pool(d->shared_pool);
+ /* destroy the connection object */
+ close_connection(connection);
return NULL;
}
#endif
+#endif
+
/* Write the PID of the current process as a decimal number, followed by a
newline to the file FILENAME, using POOL for temporary allocations. */
static svn_error_t *write_pid_file(const char *filename, apr_pool_t *pool)
@@ -591,14 +649,19 @@ check_lib_versions(void)
}
-int main(int argc, const char *argv[])
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
enum run_mode run_mode = run_mode_unspecified;
svn_boolean_t foreground = FALSE;
- apr_socket_t *sock, *usock;
+ apr_socket_t *sock;
apr_file_t *in_file, *out_file;
apr_sockaddr_t *sa;
- apr_pool_t *pool;
svn_error_t *err;
apr_getopt_t *os;
int opt;
@@ -606,17 +669,16 @@ int main(int argc, const char *argv[])
const char *arg;
apr_status_t status;
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
+#if APR_HAS_THREADS && !HAVE_THREADPOOLS
apr_threadattr_t *tattr;
apr_thread_t *tid;
#endif
-#endif
+ svn_boolean_t is_multi_threaded;
enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
+ apr_hash_t *fs_config = NULL;
+ svn_boolean_t cache_fulltexts = TRUE;
+ svn_boolean_t cache_txdeltas = TRUE;
+ svn_boolean_t cache_revprops = FALSE;
apr_uint16_t port = SVN_RA_SVN_PORT;
const char *host = NULL;
int family = APR_INET;
@@ -634,30 +696,17 @@ int main(int argc, const char *argv[])
svn_node_kind_t kind;
svn_root_pools__t *socket_pools;
- /* Initialize the app. */
- if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- /* Create our top-level pool. */
- pool = svn_pool_create(NULL);
-
#ifdef SVN_HAVE_SASL
- SVN_INT_ERR(cyrus_init(pool));
+ SVN_ERR(cyrus_init(pool));
#endif
/* Check library versions */
- err = check_lib_versions();
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ SVN_ERR(check_lib_versions());
/* Initialize the FS library. */
- err = svn_fs_initialize(pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ SVN_ERR(svn_fs_initialize(pool));
- err = svn_cmdline__getopt_init(&os, argc, argv, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
params.root = "/";
params.tunnel = FALSE;
@@ -667,12 +716,12 @@ int main(int argc, const char *argv[])
params.cfg = NULL;
params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
params.logger = NULL;
+ params.config_pool = NULL;
+ params.authz_pool = NULL;
+ params.repos_pool = NULL;
params.vhost = FALSE;
params.username_case = CASE_ASIS;
params.memory_cache_size = (apr_uint64_t)-1;
- params.cache_fulltexts = TRUE;
- params.cache_txdeltas = TRUE;
- params.cache_revprops = FALSE;
params.zero_copy_limit = 0;
params.error_check_interval = 4096;
@@ -682,7 +731,11 @@ int main(int argc, const char *argv[])
if (APR_STATUS_IS_EOF(status))
break;
if (status != APR_SUCCESS)
- usage(argv[0], pool);
+ {
+ usage(argv[0], pool);
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
+ }
switch (opt)
{
case '6':
@@ -694,7 +747,7 @@ int main(int argc, const char *argv[])
case 'h':
help(pool);
- break;
+ return SVN_NO_ERROR;
case 'q':
quiet = TRUE;
@@ -735,10 +788,8 @@ int main(int argc, const char *argv[])
err = svn_cstring_strtoui64(&val, arg, 0, APR_UINT16_MAX, 10);
if (err)
- return svn_cmdline_handle_exit_error(
- svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Invalid port '%s'"), arg),
- pool, "svnserve: ");
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Invalid port '%s'"), arg);
port = (apr_uint16_t)val;
}
break;
@@ -768,23 +819,18 @@ int main(int argc, const char *argv[])
break;
case 'r':
- SVN_INT_ERR(svn_utf_cstring_to_utf8(¶ms.root, arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(¶ms.root, arg, pool));
- err = svn_io_check_resolved_path(params.root, &kind, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ SVN_ERR(svn_io_check_resolved_path(params.root, &kind, pool));
if (kind != svn_node_dir)
{
- svn_error_clear
- (svn_cmdline_fprintf
- (stderr, pool,
- _("svnserve: Root path '%s' does not exist "
- "or is not a directory.\n"), params.root));
- return EXIT_FAILURE;
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Root path '%s' does not exist "
+ "or is not a directory"), params.root);
}
params.root = svn_dirent_internal_style(params.root, pool);
- SVN_INT_ERR(svn_dirent_get_absolute(¶ms.root, params.root, pool));
+ SVN_ERR(svn_dirent_get_absolute(¶ms.root, params.root, pool));
break;
case 'R':
@@ -809,18 +855,15 @@ int main(int argc, const char *argv[])
break;
case SVNSERVE_OPT_CACHE_TXDELTAS:
- params.cache_txdeltas
- = svn_tristate__from_word(arg) == svn_tristate_true;
+ cache_txdeltas = svn_tristate__from_word(arg) == svn_tristate_true;
break;
case SVNSERVE_OPT_CACHE_FULLTEXTS:
- params.cache_fulltexts
- = svn_tristate__from_word(arg) == svn_tristate_true;
+ cache_fulltexts = svn_tristate__from_word(arg) == svn_tristate_true;
break;
case SVNSERVE_OPT_CACHE_REVPROPS:
- params.cache_revprops
- = svn_tristate__from_word(arg) == svn_tristate_true;
+ cache_revprops = svn_tristate__from_word(arg) == svn_tristate_true;
break;
case SVNSERVE_OPT_CLIENT_SPEED:
@@ -851,17 +894,16 @@ int main(int argc, const char *argv[])
#endif
case SVNSERVE_OPT_CONFIG_FILE:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&config_filename, arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&config_filename, arg, pool));
config_filename = svn_dirent_internal_style(config_filename, pool);
- SVN_INT_ERR(svn_dirent_get_absolute(&config_filename, config_filename,
- pool));
+ SVN_ERR(svn_dirent_get_absolute(&config_filename, config_filename,
+ pool));
break;
case SVNSERVE_OPT_PID_FILE:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&pid_filename, arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&pid_filename, arg, pool));
pid_filename = svn_dirent_internal_style(pid_filename, pool);
- SVN_INT_ERR(svn_dirent_get_absolute(&pid_filename, pid_filename,
- pool));
+ SVN_ERR(svn_dirent_get_absolute(&pid_filename, pid_filename, pool));
break;
case SVNSERVE_OPT_VIRTUAL_HOST:
@@ -869,10 +911,9 @@ int main(int argc, const char *argv[])
break;
case SVNSERVE_OPT_LOG_FILE:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
log_filename = svn_dirent_internal_style(log_filename, pool);
- SVN_INT_ERR(svn_dirent_get_absolute(&log_filename, log_filename,
- pool));
+ SVN_ERR(svn_dirent_get_absolute(&log_filename, log_filename, pool));
break;
}
@@ -880,12 +921,16 @@ int main(int argc, const char *argv[])
if (is_version)
{
- SVN_INT_ERR(version(quiet, pool));
- exit(0);
+ SVN_ERR(version(quiet, pool));
+ return SVN_NO_ERROR;
}
if (os->ind != argc)
- usage(argv[0], pool);
+ {
+ usage(argv[0], pool);
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
+ }
if (mode_opt_count != 1)
{
@@ -898,6 +943,8 @@ int main(int argc, const char *argv[])
#endif
stderr, pool));
usage(argv[0], pool);
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
if (handling_opt_count > 1)
@@ -906,31 +953,56 @@ int main(int argc, const char *argv[])
_("You may only specify one of -T or --single-thread\n"),
stderr, pool));
usage(argv[0], pool);
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
+ /* construct object pools */
+ is_multi_threaded = handling_mode == connection_mode_thread;
+ fs_config = apr_hash_make(pool);
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
+ cache_txdeltas ? "1" :"0");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
+ cache_fulltexts ? "1" :"0");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
+ cache_revprops ? "2" :"0");
+
+ SVN_ERR(svn_repos__config_pool_create(¶ms.config_pool,
+ is_multi_threaded,
+ pool));
+ SVN_ERR(svn_repos__authz_pool_create(¶ms.authz_pool,
+ params.config_pool,
+ is_multi_threaded,
+ pool));
+ SVN_ERR(svn_repos__repos_pool_create(¶ms.repos_pool,
+ fs_config,
+ is_multi_threaded,
+ pool));
+
/* If a configuration file is specified, load it and any referenced
* password and authorization files. */
if (config_filename)
{
params.base = svn_dirent_dirname(config_filename, pool);
- SVN_INT_ERR(svn_config_read3(¶ms.cfg, config_filename,
- TRUE, /* must_exist */
- FALSE, /* section_names_case_sensitive */
- FALSE, /* option_names_case_sensitive */
- pool));
+ SVN_ERR(svn_repos__config_pool_get(¶ms.cfg, NULL,
+ params.config_pool,
+ config_filename,
+ TRUE, /* must_exist */
+ FALSE, /* names_case_sensitive */
+ NULL,
+ pool));
}
if (log_filename)
- SVN_INT_ERR(logger__create(¶ms.logger, log_filename, pool));
+ SVN_ERR(logger__create(¶ms.logger, log_filename, pool));
+ else if (run_mode == run_mode_listen_once)
+ SVN_ERR(logger__create_for_stderr(¶ms.logger, pool));
if (params.tunnel_user && run_mode != run_mode_tunnel)
{
- svn_error_clear
- (svn_cmdline_fprintf
- (stderr, pool,
- _("Option --tunnel-user is only valid in tunnel mode.\n")));
- exit(1);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Option --tunnel-user is only valid in tunnel mode"));
}
if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
@@ -944,15 +1016,13 @@ int main(int argc, const char *argv[])
status = apr_file_open_stdin(&in_file, pool);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't open stdin"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't open stdin"));
}
status = apr_file_open_stdout(&out_file, pool);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't open stdout"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't open stdout"));
}
/* Use a subpool for the connection to ensure that if SASL is used
@@ -964,8 +1034,10 @@ int main(int argc, const char *argv[])
params.zero_copy_limit,
params.error_check_interval,
connection_pool);
- svn_error_clear(serve(conn, ¶ms, connection_pool));
- exit(0);
+ err = serve(conn, ¶ms, connection_pool);
+ svn_pool_destroy(connection_pool);
+
+ return err;
}
#ifdef WIN32
@@ -1010,7 +1082,8 @@ int main(int argc, const char *argv[])
}
svn_error_clear(err);
- exit(1);
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* The service is now in the "starting" state. Before the SCM will
@@ -1055,8 +1128,7 @@ int main(int argc, const char *argv[])
sockaddr_info_flags, pool);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't get address info"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't get address info"));
}
@@ -1069,25 +1141,32 @@ int main(int argc, const char *argv[])
#endif
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't create server socket"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't create server socket"));
}
/* Prevents "socket in use" errors when server is killed and quickly
* restarted. */
- apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
+ status = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
+ if (status)
+ {
+ return svn_error_wrap_apr(status, _("Can't set options on server socket"));
+ }
status = apr_socket_bind(sock, sa);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't bind server socket"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't bind server socket"));
}
- apr_socket_listen(sock, ACCEPT_BACKLOG);
+ status = apr_socket_listen(sock, ACCEPT_BACKLOG);
+ if (status)
+ {
+ return svn_error_wrap_apr(status, _("Can't listen on server socket"));
+ }
#if APR_HAS_FORK
if (run_mode != run_mode_listen_once && !foreground)
+ /* ### ignoring errors... */
apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
apr_signal(SIGCHLD, sigchld_handler);
@@ -1106,7 +1185,7 @@ int main(int argc, const char *argv[])
#endif
if (pid_filename)
- SVN_INT_ERR(write_pid_file(pid_filename, pool));
+ SVN_ERR(write_pid_file(pid_filename, pool));
#ifdef WIN32
status = apr_os_sock_get(&winservice_svnserve_accept_socket, sock);
@@ -1148,14 +1227,10 @@ int main(int argc, const char *argv[])
/* 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: ");
+ SVN_ERR(svn_root_pools__create(&socket_pools));
#if APR_HAS_THREADS
- err = svn_root_pools__create(&connection_pools);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ SVN_ERR(svn_root_pools__create(&connection_pools));
#endif
#if HAVE_THREADPOOLS
@@ -1168,8 +1243,7 @@ int main(int argc, const char *argv[])
pool);
if (status)
{
- err = svn_error_wrap_apr (status, _("Can't create thread pool"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ return svn_error_wrap_apr(status, _("Can't create thread pool"));
}
/* let idle threads linger for a while in case more requests are
@@ -1179,82 +1253,45 @@ int main(int argc, const char *argv[])
/* don't queue requests unless we reached the worker thread limit */
apr_thread_pool_threshold_set(threads, 0);
}
+ else
+ {
+ threads = NULL;
+ }
#endif
while (1)
{
- apr_pool_t *socket_pool;
-
-#ifdef WIN32
- if (winservice_is_stopping())
- return ERROR_SUCCESS;
-#endif
-
- /* Non-standard pool handling. The main thread never blocks to join
- the connection threads so it cannot clean up after each one. So
- separate pools that can be cleared at thread exit are used. */
-
- socket_pool = svn_root_pools__acquire_pool(socket_pools);
-
- 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,
- socket_pool) == APR_CHILD_DONE)
- ;
- }
- if (APR_STATUS_IS_EINTR(status)
- || APR_STATUS_IS_ECONNABORTED(status)
- || APR_STATUS_IS_ECONNRESET(status))
- {
- svn_root_pools__release_pool(socket_pool, socket_pools);
- continue;
- }
- if (status)
- {
- err = svn_error_wrap_apr
- (status, _("Can't accept client connection"));
- return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
- }
-
+ connection_t *connection = NULL;
+ SVN_ERR(accept_connection(&connection, sock, socket_pools, ¶ms,
+ handling_mode));
if (run_mode == run_mode_listen_once)
{
- err = serve_socket(usock, ¶ms, socket_pool);
-
- if (err)
- svn_handle_error2(err, stdout, FALSE, "svnserve: ");
- svn_error_clear(err);
-
- apr_socket_close(usock);
- apr_socket_close(sock);
- exit(0);
+ err = serve_socket(connection, connection->pool);
+ close_connection(connection);
+ return err;
}
switch (handling_mode)
{
case connection_mode_fork:
#if APR_HAS_FORK
- status = apr_proc_fork(&proc, socket_pool);
+ status = apr_proc_fork(&proc, connection->pool);
if (status == APR_INCHILD)
{
+ /* the child would't listen to the main server's socket */
apr_socket_close(sock);
- svn_error_clear(serve_socket(usock, ¶ms, socket_pool));
- apr_socket_close(usock);
- exit(0);
- }
- else if (status == APR_INPARENT)
- {
- apr_socket_close(usock);
+
+ /* serve_socket() logs any error it returns, so ignore it. */
+ svn_error_clear(serve_socket(connection, connection->pool));
+ close_connection(connection);
+ return SVN_NO_ERROR;
}
- else
+ else if (status != APR_INPARENT)
{
err = svn_error_wrap_apr(status, "apr_proc_fork");
logger__log_error(params.logger, err, NULL, NULL);
svn_error_clear(err);
- apr_socket_close(usock);
}
- svn_root_pools__release_pool(socket_pool, socket_pools);
#endif
break;
@@ -1263,52 +1300,79 @@ 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(socket_pool, socket_pools);
+ attach_connection(connection);
- thread_data = apr_palloc(socket_pool, sizeof(*thread_data));
- thread_data->usock = usock;
- thread_data->params = ¶ms;
- thread_data->shared_pool = shared_pool;
#if HAVE_THREADPOOLS
- status = apr_thread_pool_push(threads, serve_thread, thread_data,
+ status = apr_thread_pool_push(threads, serve_thread, connection,
0, NULL);
#else
- status = apr_threadattr_create(&tattr, socket_pool);
+ status = apr_threadattr_create(&tattr, connection->pool);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't create threadattr"));
- svn_handle_error2(err, stderr, FALSE, "svnserve: ");
- svn_error_clear(err);
- exit(1);
+ return svn_error_wrap_apr(status, _("Can't create threadattr"));
}
status = apr_threadattr_detach_set(tattr, 1);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't set detached state"));
- svn_handle_error2(err, stderr, FALSE, "svnserve: ");
- svn_error_clear(err);
- exit(1);
+ return svn_error_wrap_apr(status, _("Can't set detached state"));
}
- status = apr_thread_create(&tid, tattr, serve_thread, thread_data,
- shared_pool->pool);
+ status = apr_thread_create(&tid, tattr, serve_thread, connection,
+ connection->pool);
#endif
if (status)
{
- err = svn_error_wrap_apr(status, THREAD_ERROR_MSG);
- svn_handle_error2(err, stderr, FALSE, "svnserve: ");
- svn_error_clear(err);
- exit(1);
+ return svn_error_wrap_apr(status, THREAD_ERROR_MSG);
}
- release_shared_pool(shared_pool);
#endif
break;
case connection_mode_single:
/* Serve one connection at a time. */
- svn_error_clear(serve_socket(usock, ¶ms, socket_pool));
- svn_root_pools__release_pool(socket_pool, socket_pools);
+ /* serve_socket() logs any error it returns, so ignore it. */
+ svn_error_clear(serve_socket(connection, connection->pool));
}
+
+ close_connection(connection);
}
/* NOTREACHED */
}
+
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
+
+ /* Initialize the app. */
+ if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. */
+ pool = svn_pool_create(NULL);
+
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svnserve: ");
+ }
+
+#if HAVE_THREADPOOLS
+ /* Explicitly wait for all threads to exit. As we found out with similar
+ code in our C test framework, the memory pool cleanup below cannot be
+ trusted to do the right thing. */
+ if (threads)
+ apr_thread_pool_destroy(threads);
+#endif
+
+ /* this will also close the server's socket */
+ svn_pool_destroy(pool);
+ return exit_code;
+}
Modified: subversion/branches/fsfs-improvements/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/svnsync/svnsync.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/fsfs-improvements/subversion/svnsync/svnsync.c Wed Nov 27 07:53:29 2013
@@ -1875,8 +1875,13 @@ help_cmd(apr_getopt_t *os, void *baton,
/*** Main ***/
-int
-main(int argc, const char *argv[])
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
const svn_opt_subcommand_desc2_t *subcommand = NULL;
apr_array_header_t *received_opts;
@@ -1884,7 +1889,6 @@ main(int argc, const char *argv[])
svn_config_t *config;
apr_status_t apr_err;
apr_getopt_t *os;
- apr_pool_t *pool;
svn_error_t *err;
int opt_id, i;
const char *username = NULL, *source_username = NULL, *sync_username = NULL;
@@ -1893,23 +1897,10 @@ main(int argc, const char *argv[])
const char *source_prop_encoding = NULL;
svn_boolean_t force_interactive = FALSE;
- if (svn_cmdline_init("svnsync", stderr) != EXIT_SUCCESS)
- {
- return EXIT_FAILURE;
- }
-
- err = check_lib_versions();
- if (err)
- return svn_cmdline_handle_exit_error(err, NULL, "svnsync: ");
-
- /* Create our top-level pool. Use a separate mutexless allocator,
- * given this application is single threaded.
- */
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+ /* Check library versions */
+ SVN_ERR(check_lib_versions());
- err = svn_ra_initialize(pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ SVN_ERR(svn_ra_initialize(pool));
/* Initialize the option baton. */
memset(&opt_baton, 0, sizeof(opt_baton));
@@ -1920,14 +1911,12 @@ main(int argc, const char *argv[])
if (argc <= 1)
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
- err = svn_cmdline__getopt_init(&os, argc, argv, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
os->interleave = 1;
@@ -1941,9 +1930,9 @@ main(int argc, const char *argv[])
break;
else if (apr_err)
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
APR_ARRAY_PUSH(received_opts, int) = opt_id;
@@ -2005,12 +1994,9 @@ main(int argc, const char *argv[])
apr_array_make(pool, 1,
sizeof(svn_cmdline__config_argument_t*));
- err = svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool);
- if (!err)
- err = svn_cmdline__parse_config_option(config_options,
- opt_arg, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ SVN_ERR(svn_cmdline__parse_config_option(config_options,
+ opt_arg, pool));
break;
case svnsync_opt_source_prop_encoding:
@@ -2044,13 +2030,11 @@ main(int argc, const char *argv[])
opt_arg, pool) != 0)
{
const char *utf8_opt_arg;
- err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
- if (! err)
- err = svn_error_createf(
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ return svn_error_createf(
SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error in revision argument '%s'"),
utf8_opt_arg);
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
}
/* We only allow numbers and 'HEAD'. */
@@ -2060,10 +2044,9 @@ main(int argc, const char *argv[])
(opt_baton.end_rev.kind != svn_opt_revision_head) &&
(opt_baton.end_rev.kind != svn_opt_revision_unspecified)))
{
- err = svn_error_createf(
+ return svn_error_createf(
SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Invalid revision range '%s' provided"), opt_arg);
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
}
break;
@@ -2074,14 +2057,14 @@ main(int argc, const char *argv[])
default:
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
- if(opt_err)
- return svn_cmdline_handle_exit_error(opt_err, pool, "svnsync: ");
+ if (opt_err)
+ return opt_err;
}
if (opt_baton.help)
@@ -2091,10 +2074,9 @@ main(int argc, const char *argv[])
* exclusive. */
if (opt_baton.non_interactive && force_interactive)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--non-interactive and --force-interactive "
- "are mutually exclusive"));
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--non-interactive and --force-interactive "
+ "are mutually exclusive"));
}
else
opt_baton.non_interactive = !svn_cmdline__be_interactive(
@@ -2108,12 +2090,11 @@ main(int argc, const char *argv[])
&& (source_username || sync_username
|| source_password || sync_password))
{
- err = svn_error_create
+ return svn_error_create
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Cannot use --username or --password with any of "
"--source-username, --source-password, --sync-username, "
"or --sync-password.\n"));
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
}
if (username)
{
@@ -2133,24 +2114,20 @@ main(int argc, const char *argv[])
/* Disallow mixing of --steal-lock and --disable-locking. */
if (opt_baton.steal_lock && opt_baton.disable_locking)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--disable-locking and --steal-lock are "
- "mutually exclusive"));
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--disable-locking and --steal-lock are "
+ "mutually exclusive"));
}
/* --trust-server-cert can only be used with --non-interactive */
if (opt_baton.trust_server_cert && !opt_baton.non_interactive)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--trust-server-cert requires "
- "--non-interactive"));
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--trust-server-cert requires "
+ "--non-interactive"));
}
- err = svn_config_ensure(opt_baton.config_dir, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "synsync: ");
+ SVN_ERR(svn_config_ensure(opt_baton.config_dir, pool));
if (subcommand == NULL)
{
@@ -2169,9 +2146,9 @@ main(int argc, const char *argv[])
}
else
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
else
@@ -2181,9 +2158,9 @@ main(int argc, const char *argv[])
first_arg);
if (subcommand == NULL)
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
}
@@ -2204,23 +2181,20 @@ main(int argc, const char *argv[])
svn_opt_format_option(&optstr, badopt, FALSE, pool);
if (subcommand->name[0] == '-')
{
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
+ SVN_ERR(help_cmd(NULL, NULL, pool));
}
else
{
- err = svn_error_createf
+ return svn_error_createf
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Subcommand '%s' doesn't accept option '%s'\n"
"Type 'svnsync help %s' for usage.\n"),
subcommand->name, optstr, subcommand->name);
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
}
}
}
- err = svn_config_get_config(&opt_baton.config, opt_baton.config_dir, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ SVN_ERR(svn_config_get_config(&opt_baton.config, opt_baton.config_dir, pool));
/* Update the options in the config */
if (config_options)
@@ -2296,10 +2270,40 @@ main(int argc, const char *argv[])
_("Try 'svnsync help' for more info"));
}
- return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
+ return err;
}
- svn_pool_destroy(pool);
+ return SVN_NO_ERROR;
+}
- return EXIT_SUCCESS;
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
+
+ /* Initialize the app. */
+ if (svn_cmdline_init("svnsync", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. Use a separate mutexless allocator,
+ * given this application is single threaded.
+ */
+ pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svnsync: ");
+ }
+
+ svn_pool_destroy(pool);
+ return exit_code;
}
Modified: subversion/branches/fsfs-improvements/subversion/svnversion/svnversion.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/svnversion/svnversion.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/svnversion/svnversion.c (original)
+++ subversion/branches/fsfs-improvements/subversion/svnversion/svnversion.c Wed Nov 27 07:53:29 2013
@@ -47,7 +47,6 @@ usage(apr_pool_t *pool)
{
svn_error_clear(svn_cmdline_fprintf
(stderr, pool, _("Type 'svnversion --help' for usage.\n")));
- exit(1);
}
@@ -97,7 +96,6 @@ help(const apr_getopt_option_t *options,
++options;
}
svn_error_clear(svn_cmdline_fprintf(stdout, pool, "\n"));
- exit(0);
}
@@ -117,16 +115,19 @@ check_lib_versions(void)
}
/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ *
* Why is this not an svn subcommand? I have this vague idea that it could
* be run as part of the build process, with the output embedded in the svn
* program. Obviously we don't want to have to run svn when building svn.
*/
-int
-main(int argc, const char *argv[])
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
const char *wc_path, *trail_url;
const char *local_abspath;
- apr_pool_t *pool;
svn_wc_revision_status_t *res;
svn_boolean_t no_newline = FALSE, committed = FALSE;
svn_error_t *err;
@@ -146,33 +147,18 @@ main(int argc, const char *argv[])
{0, 0, 0, 0}
};
- /* Initialize the app. */
- if (svn_cmdline_init("svnversion", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- /* Create our top-level pool. Use a separate mutexless allocator,
- * given this application is single threaded.
- */
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
/* Check library versions */
- err = check_lib_versions();
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
+ SVN_ERR(check_lib_versions());
#if defined(WIN32) || defined(__CYGWIN__)
/* Set the working copy administrative directory name. */
if (getenv("SVN_ASP_DOT_NET_HACK"))
{
- err = svn_wc_set_adm_dir("_svn", pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
+ SVN_ERR(svn_wc_set_adm_dir("_svn", pool));
}
#endif
- err = svn_cmdline__getopt_init(&os, argc, argv, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
os->interleave = 1;
while (1)
@@ -183,7 +169,11 @@ main(int argc, const char *argv[])
if (APR_STATUS_IS_EOF(status))
break;
if (status != APR_SUCCESS)
- usage(pool); /* this will exit() */
+ {
+ *exit_code = EXIT_FAILURE;
+ usage(pool);
+ return SVN_NO_ERROR;
+ }
switch (opt)
{
@@ -198,35 +188,39 @@ main(int argc, const char *argv[])
break;
case 'h':
help(options, pool);
- break;
+ return SVN_NO_ERROR;
case SVNVERSION_OPT_VERSION:
is_version = TRUE;
break;
default:
- usage(pool); /* this will exit() */
+ *exit_code = EXIT_FAILURE;
+ usage(pool);
+ return SVN_NO_ERROR;
}
}
if (is_version)
{
- SVN_INT_ERR(version(quiet, pool));
- exit(0);
+ SVN_ERR(version(quiet, pool));
+ return SVN_NO_ERROR;
}
if (os->ind > argc || os->ind < argc - 2)
- usage(pool); /* this will exit() */
+ {
+ *exit_code = EXIT_FAILURE;
+ usage(pool);
+ return SVN_NO_ERROR;
+ }
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&wc_path,
- (os->ind < argc) ? os->argv[os->ind]
- : ".",
- pool));
-
- SVN_INT_ERR(svn_opt__arg_canonicalize_path(&wc_path, wc_path, pool));
- SVN_INT_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool));
- SVN_INT_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&wc_path,
+ (os->ind < argc) ? os->argv[os->ind] : ".",
+ pool));
+
+ SVN_ERR(svn_opt__arg_canonicalize_path(&wc_path, wc_path, pool));
+ SVN_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool));
+ SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));
if (os->ind+1 < argc)
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&trail_url, os->argv[os->ind+1],
- pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&trail_url, os->argv[os->ind+1], pool));
else
trail_url = NULL;
@@ -241,63 +235,87 @@ main(int argc, const char *argv[])
svn_error_clear(err);
- SVN_INT_ERR(svn_io_check_special_path(local_abspath, &kind, &special,
- pool));
+ SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &special, pool));
if (special)
- SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned symlink%s"),
- no_newline ? "" : "\n"));
+ SVN_ERR(svn_cmdline_printf(pool, _("Unversioned symlink%s"),
+ no_newline ? "" : "\n"));
else if (kind == svn_node_dir)
- SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned directory%s"),
- no_newline ? "" : "\n"));
+ SVN_ERR(svn_cmdline_printf(pool, _("Unversioned directory%s"),
+ no_newline ? "" : "\n"));
else if (kind == svn_node_file)
- SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned file%s"),
- no_newline ? "" : "\n"));
+ SVN_ERR(svn_cmdline_printf(pool, _("Unversioned file%s"),
+ no_newline ? "" : "\n"));
else
{
- SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
- kind == svn_node_none
- ? _("'%s' doesn't exist\n")
- : _("'%s' is of unknown type\n"),
- svn_dirent_local_style(local_abspath,
- pool)));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool,
+ kind == svn_node_none
+ ? _("'%s' doesn't exist\n")
+ : _("'%s' is of unknown type\n"),
+ svn_dirent_local_style(local_abspath,
+ pool)));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
- svn_pool_destroy(pool);
- return EXIT_SUCCESS;
+ return SVN_NO_ERROR;
}
- SVN_INT_ERR(err);
+ SVN_ERR(err);
if (! SVN_IS_VALID_REVNUM(res->min_rev))
{
/* Local uncommitted modifications, no revision info was found. */
- SVN_INT_ERR(svn_cmdline_printf(pool, _("Uncommitted local addition, "
- "copy or move%s"),
- no_newline ? "" : "\n"));
- svn_pool_destroy(pool);
- return EXIT_SUCCESS;
+ SVN_ERR(svn_cmdline_printf(pool, _("Uncommitted local addition, "
+ "copy or move%s"),
+ no_newline ? "" : "\n"));
+ return SVN_NO_ERROR;
}
/* Build compact '123[:456]M?S?' string. */
- SVN_INT_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
+ SVN_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
if (res->min_rev != res->max_rev)
- SVN_INT_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
+ SVN_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
if (res->modified)
- SVN_INT_ERR(svn_cmdline_fputs("M", stdout, pool));
+ SVN_ERR(svn_cmdline_fputs("M", stdout, pool));
if (res->switched)
- SVN_INT_ERR(svn_cmdline_fputs("S", stdout, pool));
+ SVN_ERR(svn_cmdline_fputs("S", stdout, pool));
if (res->sparse_checkout)
- SVN_INT_ERR(svn_cmdline_fputs("P", stdout, pool));
+ SVN_ERR(svn_cmdline_fputs("P", stdout, pool));
if (! no_newline)
- SVN_INT_ERR(svn_cmdline_fputs("\n", stdout, pool));
+ SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
- svn_pool_destroy(pool);
+ return SVN_NO_ERROR;
+}
- /* Flush stdout to make sure that the user will see any printing errors. */
- SVN_INT_ERR(svn_cmdline_fflush(stdout));
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
- return EXIT_SUCCESS;
+ /* Initialize the app. */
+ if (svn_cmdline_init("svnversion", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. Use a separate mutexless allocator,
+ * given this application is single threaded.
+ */
+ pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svnversion: ");
+ }
+
+ svn_pool_destroy(pool);
+ return exit_code;
}
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/checkout_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/checkout_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/checkout_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/checkout_tests.py Wed Nov 27 07:53:29 2013
@@ -1116,8 +1116,25 @@ def checkout_wc_from_drive(sbox):
'B/F' : Item(status='A '),
'B/lambda' : Item(status='A '),
})
+
+ expected_wc = wc.State('', {
+ 'C' : Item(),
+ 'B/E/beta' : Item(contents="This is the file 'beta'.\n"),
+ 'B/E/alpha' : Item(contents="This is the file 'alpha'.\n"),
+ 'B/lambda' : Item(contents="This is the file 'lambda'.\n"),
+ 'B/F' : Item(),
+ 'D/H/omega' : Item(contents="This is the file 'omega'.\n"),
+ 'D/H/psi' : Item(contents="This is the file 'psi'.\n"),
+ 'D/H/chi' : Item(contents="This is the file 'chi'.\n"),
+ 'D/G/rho' : Item(contents="This is the file 'rho'.\n"),
+ 'D/G/tau' : Item(contents="This is the file 'tau'.\n"),
+ 'D/G/pi' : Item(contents="This is the file 'pi'.\n"),
+ 'D/gamma' : Item(contents="This is the file 'gamma'.\n"),
+ 'mu' : Item(contents="This is the file 'mu'.\n"),
+ })
+
svntest.actions.run_and_verify_checkout(repo_url + '/A', wc2_dir,
- expected_output, None,
+ expected_output, expected_wc,
None, None, None, None)
wc3_dir = sbox.add_wc_path('3')
@@ -1133,8 +1150,18 @@ def checkout_wc_from_drive(sbox):
'gamma' : Item(status='A '),
})
+ expected_wc = wc.State('', {
+ 'H/chi' : Item(contents="This is the file 'chi'.\n"),
+ 'H/psi' : Item(contents="This is the file 'psi'.\n"),
+ 'H/omega' : Item(contents="This is the file 'omega'.\n"),
+ 'G/pi' : Item(contents="This is the file 'pi'.\n"),
+ 'G/tau' : Item(contents="This is the file 'tau'.\n"),
+ 'G/rho' : Item(contents="This is the file 'rho'.\n"),
+ 'gamma' : Item(contents="This is the file 'gamma'.\n"),
+ })
+
svntest.actions.run_and_verify_checkout(repo_url + '/A/D', wc3_dir,
- expected_output, None,
+ expected_output, expected_wc,
None, None, None, None)
finally:
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/davautocheck.sh?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/davautocheck.sh Wed Nov 27 07:53:29 2013
@@ -429,9 +429,17 @@ User $(id -un)
Group $(id -gn)
__EOF__
else
+HTTPD_LOCK="$HTTPD_ROOT/lock"
+mkdir "$HTTPD_LOCK" \
+ || fail "couldn't create lock directory '$HTTPD_LOCK'"
cat >> "$HTTPD_CFG" <<__EOF__
-# TODO: maybe uncomment this for prefork,worker MPMs only?
-# Mutex file:lock mpm-accept
+# worker and prefork MUST have a mpm-accept lockfile in 2.3.0+
+<IfModule worker.c>
+ Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
+<IfModule prefork.c>
+ Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
__EOF__
fi
@@ -447,7 +455,7 @@ cat >> "$HTTPD_CFG" <<__EOF__
Listen $HTTPD_PORT
ServerName localhost
PidFile "$HTTPD_PID"
-LogFormat "%h %l %u %t \"%r\" %>s %b" common
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%f\"" common
CustomLog "$HTTPD_ACCESS_LOG" common
ErrorLog "$HTTPD_ERROR_LOG"
LogLevel debug
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/diff_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/diff_tests.py Wed Nov 27 07:53:29 2013
@@ -4648,6 +4648,26 @@ def diff_local_missing_obstruction(sbox)
'diff', wc_dir)
+@Issue(4444)
+def diff_move_inside_copy(sbox):
+ "diff copied-along child that contains a moved file"
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ d_path = 'A/D'
+ d_copy = 'A/D-copy'
+ h_path = 'A/D-copy/H'
+ chi_path = '%s/chi' % h_path
+ chi_moved = '%s/chi-moved' % h_path
+
+ sbox.simple_copy(d_path, d_copy)
+ sbox.simple_move(chi_path, chi_moved)
+ sbox.simple_append(chi_moved, 'a new line')
+
+ # Bug: Diffing the copied-along parent directory asserts
+ svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
+ 'diff', sbox.ospath(h_path))
+
########################################################################
#Run the tests
@@ -4729,6 +4749,7 @@ test_list = [ None,
diff_repos_empty_file_addition,
diff_missing_tree_conflict_victim,
diff_local_missing_obstruction,
+ diff_move_inside_copy,
]
if __name__ == '__main__':
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/move_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/move_tests.py Wed Nov 27 07:53:29 2013
@@ -1433,7 +1433,6 @@ def move_many_update_delete(sbox):
# 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"
@@ -1457,7 +1456,7 @@ def move_many_update_add(sbox):
'B/A/A' : Item(status=' ', treeconflict='U'),
'B/A/A/BB' : Item(status=' ', treeconflict='A'),
# And while resolving
- 'A/A/' : Item(status=' ', treeconflict='C')
+ 'A/A' : Item(status=' ', treeconflict='C')
})
expected_status.tweak('',
@@ -1485,9 +1484,17 @@ def move_many_update_add(sbox):
expected_status.tweak('',
'B', 'B/A', 'B/A/A', 'B/A/A/A',
'C', 'C/A', 'C/A/A', 'C/A/A/A',
+ 'B/A/A/BB',
wc_rev='4')
+ expected_status.add({
+ 'C/A/A/BB' : Item(status='D ', wc_rev='4'),
+ })
+
+ expected_status.tweak('A/A/A', treeconflict='C')
+
expected_output = svntest.wc.State(wc_dir, {
+ 'A/A/A' : Item(status=' ', treeconflict='C'),
'C/A' : Item(status=' ', treeconflict='C'),
'C/A/A' : Item(status=' ', treeconflict='U'),
'C/A/A/BB' : Item(status=' ', treeconflict='A'),
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/redirect_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/redirect_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/redirect_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/redirect_tests.py Wed Nov 27 07:53:29 2013
@@ -140,6 +140,44 @@ def redirected_update(sbox):
verify_url(wc_dir, sbox.repo_url)
#----------------------------------------------------------------------
+@SkipUnless(svntest.main.is_ra_type_dav)
+def redirected_nonroot_update(sbox):
+ "redirected update of non-repos-root wc"
+
+ sbox.build(create_wc=False)
+ wc_dir = sbox.wc_dir
+ checkout_url = sbox.repo_url + '/A'
+ relocate_url = sbox.redirected_root_url() + '/A'
+
+ # Checkout a subdir of the repository root.
+ exit_code, out, err = svntest.main.run_svn(None, 'co',
+ checkout_url, wc_dir)
+ if err:
+ raise svntest.Failure
+
+ # Relocate (by cheating) the working copy to the redirect URL. When
+ # we then update, we'll expect to find ourselves automagically back
+ # to the original URL. (This is because we can't easily introduce a
+ # redirect to the Apache configuration from the test suite here.)
+ svntest.actions.no_relocate_validation()
+ exit_code, out, err = svntest.main.run_svn(None, 'sw', '--relocate',
+ checkout_url, relocate_url,
+ wc_dir)
+ svntest.actions.do_relocate_validation()
+
+ # Now update the working copy.
+ exit_code, out, err = svntest.main.run_svn(None, 'up', wc_dir)
+ if err:
+ raise svntest.Failure
+ if not re.match("^Updating '.*':", out[0]):
+ raise svntest.Failure
+ if not redirect_regex.match(out[1]):
+ raise svntest.Failure
+
+ # Verify that we have the expected URL.
+ verify_url(wc_dir, checkout_url)
+
+#----------------------------------------------------------------------
########################################################################
# Run the tests
@@ -149,6 +187,7 @@ test_list = [ None,
temporary_redirect,
redirected_checkout,
redirected_update,
+ redirected_nonroot_update,
]
if __name__ == '__main__':
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/stat_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/stat_tests.py Wed Nov 27 07:53:29 2013
@@ -2119,6 +2119,95 @@ def status_path_handling(sbox):
expected_status = svntest.actions.get_virginal_state(rel_wc_dir, 1)
svntest.actions.run_and_verify_status(rel_wc_dir, expected_status)
+def status_move_missing_direct(sbox):
+ "move information when status is called directly"
+
+ sbox.build()
+ sbox.simple_copy('A', 'Z')
+ sbox.simple_commit('')
+ sbox.simple_update('')
+
+ sbox.simple_move('Z', 'ZZ')
+ sbox.simple_move('A', 'Z')
+ sbox.simple_move('Z/B', 'ZB')
+ sbox.simple_mkdir('Z/B')
+ sbox.simple_move('ZB/E', 'Z/B/E')
+
+ # Somehow 'svn status' now shows different output for 'ZB/E'
+ # when called directly and via an ancestor, as this handles
+ # multi-layer in a different way
+
+ # Note that the status output may change over different Subversion revisions,
+ # but the status on a node should be identical anyway 'svn status' is called
+ # on it.
+
+ expected_output = [
+ 'A + %s\n' % sbox.ospath('ZB'),
+ ' > moved from %s\n' % os.path.join('..', 'Z', 'B'),
+ 'D + %s\n' % sbox.ospath('ZB/E'),
+ ' > moved to %s\n' % os.path.join('..', 'Z', 'B', 'E'),
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'status',
+ sbox.ospath('ZB'), '--depth', 'immediates')
+
+ # And calling svn status on just 'ZB/E' should have the same result for this node
+ # except that we calculate the relative path from a different base
+ expected_output = [
+ 'D + %s\n' % sbox.ospath('ZB/E'),
+ ' > moved to %s\n' % os.path.join('..', '..', 'Z', 'B', 'E'),
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'status',
+ sbox.ospath('ZB/E'), '--depth', 'empty')
+
+def status_move_missing_direct_base(sbox):
+ "move when status is called directly with base"
+
+ sbox.build()
+ sbox.simple_copy('A', 'Z')
+ sbox.simple_mkdir('Q')
+ sbox.simple_mkdir('Q/ZB')
+ sbox.simple_mkdir('Q/ZB/E')
+ sbox.simple_commit('')
+ sbox.simple_update('')
+
+ sbox.simple_rm('Q')
+ sbox.simple_mkdir('Q')
+
+ sbox.simple_move('Z', 'ZZ')
+ sbox.simple_move('A', 'Z')
+ sbox.simple_move('Z/B', 'Q/ZB')
+ sbox.simple_mkdir('Z/B')
+ sbox.simple_move('Q/ZB/E', 'Z/B/E')
+
+ # Somehow 'svn status' now shows different output for 'Q/ZB/E'
+ # when called directly and via an ancestor, as this handles
+ # multi-layer in a different way
+
+ # Note that the status output may change over different Subversion revisions,
+ # but the status on a node should be identical anyway 'svn status' is called
+ # on it.
+
+ # This test had a different result as status_move_missing_direct at the time of
+ # writing this test.
+
+ expected_output = [
+ 'A + %s\n' % sbox.ospath('Q/ZB'),
+ ' > moved from %s\n' % os.path.join('..', '..', 'Z', 'B'),
+ 'D + %s\n' % sbox.ospath('Q/ZB/E'),
+ ' > moved to %s\n' % os.path.join('..', '..', 'Z', 'B', 'E'),
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'status',
+ sbox.ospath('Q/ZB'), '--depth', 'immediates')
+
+ # And calling svn status on just 'ZB/E' should have the same result for this node,
+ # except that the moved_to information is calculated from the node itself
+ expected_output = [
+ 'D + %s\n' % sbox.ospath('Q/ZB/E'),
+ ' > moved to %s\n' % os.path.join('..', '..', '..', 'Z', 'B', 'E'),
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'status',
+ sbox.ospath('Q/ZB/E'), '--depth', 'empty')
+
########################################################################
# Run the tests
@@ -2167,6 +2256,8 @@ test_list = [ None,
status_case_changed,
move_update_timestamps,
status_path_handling,
+ status_move_missing_direct,
+ status_move_missing_direct_base,
]
if __name__ == '__main__':
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/svnadmin_tests.py Wed Nov 27 07:53:29 2013
@@ -1931,10 +1931,8 @@ def verify_invalid_path_changes(sbox):
sbox.build(create_wc = False)
repo_url = sbox.repo_url
- B_url = sbox.repo_url + '/B'
- C_url = sbox.repo_url + '/C'
- # Create A/B/E/bravo in r2.
+ # Create a number of revisions each adding a single path
for r in range(2,20):
svntest.actions.run_and_verify_svn(None, None, [],
'mkdir', '-m', 'log_msg',
@@ -1953,11 +1951,13 @@ def verify_invalid_path_changes(sbox):
# del non-existent node
set_changed_path_list(fsfs_file(sbox.repo_dir, 'revs', '6'),
- "_0.0.t5-2 del-dir false false /C\n\n")
+ "_0.0.t5-2 delete-dir false false /C\n\n")
# del existent node of the wrong kind
+ # THIS WILL NOT BE DETECTED
+ # since dump mechanism and file don't care about the types of deleted nodes
set_changed_path_list(fsfs_file(sbox.repo_dir, 'revs', '8'),
- "_0.0.t7-2 dev-file false false /B3\n\n")
+ "_0.0.t7-2 delete-file false false /B3\n\n")
# copy from non-existent node
set_changed_path_list(fsfs_file(sbox.repo_dir, 'revs', '10'),
@@ -1995,7 +1995,7 @@ def verify_invalid_path_changes(sbox):
".*Verified revision 5.",
".*Error verifying revision 6.",
".*Verified revision 7.",
- ".*Error verifying revision 8.",
+ ".*Verified revision 8.",
".*Verified revision 9.",
".*Error verifying revision 10.",
".*Verified revision 11.",
@@ -2037,6 +2037,58 @@ def verify_invalid_path_changes(sbox):
None, errput, None, "svnadmin: E165011:.*"):
raise svntest.Failure
+
+def verify_denormalized_names(sbox):
+ "detect denormalized names and name collisions"
+
+ sbox.build(create_wc = False)
+ svntest.main.safe_rmtree(sbox.repo_dir, True)
+ svntest.main.create_repos(sbox.repo_dir)
+
+ dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
+ 'svnadmin_tests_data',
+ 'normalization_check.dump')
+ load_dumpstream(sbox, open(dumpfile_location).read())
+
+ exit_code, output, errput = svntest.main.run_svnadmin(
+ "verify", "--check-ucs-normalization", sbox.repo_dir)
+
+ expected_output_regex_list = [
+ ".*Verified revision 0.",
+ # A/{Eacute}
+ "WARNING 0x0003: Denormalized directory name 'A/.*'",
+ # A/{icircumflex}{odiaeresis}ta
+ "WARNING 0x0003: Denormalized file name 'A/.*ta'",
+ ".*Verified revision 1.",
+ ".*Verified revision 2.",
+ ".*Verified revision 3.",
+ # A/{Eacute}/{aring}lpha
+ "WARNING 0x0003: Denormalized file name 'A/.*/.*lpha'",
+ "WARNING 0x0004: Duplicate representation of path 'A/.*/.*lpha'",
+ ".*Verified revision 4.",
+ ".*Verified revision 5.",
+ # Q/{aring}lpha
+ "WARNING 0x0005: Denormalized path '/Q/.*lpha'"
+ # A/{Eacute}
+ " in svn:mergeinfo property of 'A/.*'",
+ # Q/{aring}lpha
+ "WARNING 0x0006: Duplicate representation of path '/Q/.*lpha'"
+ # A/{Eacute}
+ " in svn:mergeinfo property of 'A/.*'",
+ ".*Verified revision 6."]
+
+ # The BDB backend doesn't do global metadata verification.
+ if not svntest.main.is_fs_type_bdb():
+ expected_output_regex_list.insert(0, ".*Verifying repository metadata")
+
+ exp_out = svntest.verify.RegexListOutput(expected_output_regex_list)
+
+ if svntest.verify.verify_outputs(
+ "Unexpected error while running 'svnadmin verify'.",
+ output, errput, exp_out, None):
+ raise svntest.Failure
+
+
########################################################################
# Run the tests
@@ -2075,6 +2127,7 @@ test_list = [ None,
recover_old,
verify_keep_going,
verify_invalid_path_changes,
+ verify_denormalized_names,
]
if __name__ == '__main__':
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/svntest/main.py Wed Nov 27 07:53:29 2013
@@ -2145,7 +2145,11 @@ def execute_tests(test_list, serial_only
# Remove all scratchwork: the 'pristine' repository, greek tree, etc.
# This ensures that an 'import' will happen the next time we run.
if not options.is_child_process and not options.keep_local_tmp:
- safe_rmtree(temp_dir, 1)
+ try:
+ safe_rmtree(temp_dir, 1)
+ except:
+ logger.error("ERROR: cleanup of '%s' directory failed." % temp_dir)
+ exit_code = 1
# Cleanup after ourselves.
svntest.sandbox.cleanup_deferred_test_paths()
Modified: subversion/branches/fsfs-improvements/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/cmdline/switch_tests.py?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/cmdline/switch_tests.py Wed Nov 27 07:53:29 2013
@@ -1041,7 +1041,7 @@ def switch_change_repos_root(sbox):
# Test 1: A switch that changes to a non-existing repo shouldn't work.
expected_err = ".*Unable to open repository.*|.*Could not open.*|"\
- ".*No repository found.*"
+ ".*Could not find.*|.*No repository found.*"
svntest.actions.run_and_verify_svn(None, None,
expected_err,
'switch', '--ignore-ancestry',
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_client/client-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_client/client-test.c Wed Nov 27 07:53:29 2013
@@ -735,7 +735,7 @@ test_foreign_repos_copy(const svn_test_o
SVN_ERR(create_greek_repos(&repos_url, "foreign-copy1", opts, pool));
SVN_ERR(create_greek_repos(&repos2_url, "foreign-copy2", opts, pool));
- wc_path = svn_test_data_path("test-wc-add", pool);
+ wc_path = svn_test_data_path("test-foreign-repos-copy", pool);
wc_path = svn_dirent_join(wc_path, "foreign-wc", pool);
@@ -771,6 +771,9 @@ test_foreign_repos_copy(const svn_test_o
/* ========================================================================== */
+
+int svn_test_max_threads = 3;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
@@ -778,13 +781,13 @@ struct svn_test_descriptor_t test_funcs[
"test svn_client__elide_mergeinfo_catalog"),
SVN_TEST_PASS2(test_args_to_target_array,
"test svn_client_args_to_target_array"),
- SVN_TEST_OPTS_PASS(test_patch, "test svn_client_patch"),
SVN_TEST_OPTS_PASS(test_wc_add_scenarios, "test svn_wc_add3 scenarios"),
+ SVN_TEST_OPTS_PASS(test_foreign_repos_copy, "test foreign repository copy"),
+ SVN_TEST_OPTS_PASS(test_patch, "test svn_client_patch"),
SVN_TEST_OPTS_PASS(test_copy_crash, "test a crash in svn_client_copy5"),
#ifdef TEST16K_ADD
SVN_TEST_OPTS_PASS(test_16k_add, "test adding 16k files"),
#endif
SVN_TEST_OPTS_PASS(test_youngest_common_ancestor, "test youngest_common_ancestor"),
- SVN_TEST_OPTS_PASS(test_foreign_repos_copy, "test foreign repository copy"),
SVN_TEST_NULL
};
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/random-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/random-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/random-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/random-test.c Wed Nov 27 07:53:29 2013
@@ -512,6 +512,8 @@ random_combine_test(apr_pool_t *pool)
/* The test table. */
+int svn_test_max_threads = 1;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/window-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/window-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/window-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_delta/window-test.c Wed Nov 27 07:53:29 2013
@@ -100,6 +100,8 @@ stream_window_test(apr_pool_t *pool)
/* The test table. */
+int svn_test_max_threads = 1;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c Wed Nov 27 07:53:29 2013
@@ -2950,6 +2950,9 @@ two_way_issue_3362_v2(apr_pool_t *pool)
/* ========================================================================== */
+
+int svn_test_max_threads = 4;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/parse-diff-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/parse-diff-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/parse-diff-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_diff/parse-diff-test.c Wed Nov 27 07:53:29 2013
@@ -961,6 +961,9 @@ test_parse_unidiff_lacking_trailing_eol(
/* ========================================================================== */
+
+int svn_test_max_threads = 1;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/fs-test.c Wed Nov 27 07:53:29 2013
@@ -1020,7 +1020,7 @@ static svn_error_t *
check_entry_present(svn_fs_root_t *root, const char *path,
const char *name, apr_pool_t *pool)
{
- svn_boolean_t present;
+ svn_boolean_t present = FALSE;
SVN_ERR(check_entry(root, path, name, &present, pool));
if (! present)
@@ -1037,7 +1037,7 @@ static svn_error_t *
check_entry_absent(svn_fs_root_t *root, const char *path,
const char *name, apr_pool_t *pool)
{
- svn_boolean_t present;
+ svn_boolean_t present = TRUE;
SVN_ERR(check_entry(root, path, name, &present, pool));
if (present)
@@ -5078,6 +5078,8 @@ test_fs_info_format(const svn_test_opts_
/* The test table. */
+int svn_test_max_threads = 8;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
@@ -5093,6 +5095,12 @@ struct svn_test_descriptor_t test_funcs[
"check that transaction names are not reused"),
SVN_TEST_OPTS_PASS(write_and_read_file,
"write and read a file's contents"),
+ SVN_TEST_OPTS_PASS(almostmedium_file_integrity,
+ "create and modify almostmedium file"),
+ SVN_TEST_OPTS_PASS(medium_file_integrity,
+ "create and modify medium file"),
+ SVN_TEST_OPTS_PASS(large_file_integrity,
+ "create and modify large file"),
SVN_TEST_OPTS_PASS(create_mini_tree_transaction,
"test basic file and subdirectory creation"),
SVN_TEST_OPTS_PASS(create_greek_tree_transaction,
@@ -5124,12 +5132,6 @@ struct svn_test_descriptor_t test_funcs[
"check old revisions"),
SVN_TEST_OPTS_PASS(check_all_revisions,
"after each commit, check all revisions"),
- SVN_TEST_OPTS_PASS(almostmedium_file_integrity,
- "create and modify almostmedium file"),
- SVN_TEST_OPTS_PASS(medium_file_integrity,
- "create and modify medium file"),
- SVN_TEST_OPTS_PASS(large_file_integrity,
- "create and modify large file"),
SVN_TEST_OPTS_PASS(check_root_revision,
"ensure accurate storage of root node"),
SVN_TEST_OPTS_PASS(test_node_created_rev,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/locks-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/locks-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/locks-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs/locks-test.c Wed Nov 27 07:53:29 2013
@@ -608,9 +608,9 @@ lock_expiration(const svn_test_opts_t *o
SVN_ERR(svn_fs_create_access(&access, "bubba", pool));
SVN_ERR(svn_fs_set_access(fs, access));
- /* Lock /A/D/G/rho, with an expiration 3 seconds from now. */
+ /* Lock /A/D/G/rho, with an expiration 2 seconds from now. */
SVN_ERR(svn_fs_lock(&mylock, fs, "/A/D/G/rho", NULL, "", 0,
- apr_time_now() + apr_time_from_sec(3),
+ apr_time_now() + apr_time_from_sec(2),
SVN_INVALID_REVNUM, FALSE, pool));
/* Become nobody. */
@@ -640,9 +640,9 @@ lock_expiration(const svn_test_opts_t *o
num_expected_paths, pool));
}
- /* Sleep 5 seconds, so the lock auto-expires. Anonymous commit
+ /* Sleep 2 seconds, so the lock auto-expires. Anonymous commit
should then succeed. */
- apr_sleep(apr_time_from_sec(5));
+ apr_sleep(apr_time_from_sec(3));
/* Verify that the lock auto-expired even in the recursive case. */
{
@@ -792,9 +792,13 @@ lock_out_of_date(const svn_test_opts_t *
/* The test table. */
+int svn_test_max_threads = 2;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
+ SVN_TEST_OPTS_PASS(lock_expiration,
+ "test that locks can expire"),
SVN_TEST_OPTS_PASS(lock_only,
"lock only"),
SVN_TEST_OPTS_PASS(lookup_lock_by_path,
@@ -811,8 +815,6 @@ struct svn_test_descriptor_t test_funcs[
"test that locking is enforced in final commit step"),
SVN_TEST_OPTS_PASS(lock_dir_propchange,
"dir propchange can be committed with locked child"),
- SVN_TEST_OPTS_PASS(lock_expiration,
- "test that locks can expire"),
SVN_TEST_OPTS_PASS(lock_break_steal_refresh,
"breaking, stealing, refreshing a lock"),
SVN_TEST_OPTS_PASS(lock_out_of_date,
Modified: subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_base/changes-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_base/changes-test.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_base/changes-test.c (original)
+++ subversion/branches/fsfs-improvements/subversion/tests/libsvn_fs_base/changes-test.c Wed Nov 27 07:53:29 2013
@@ -193,7 +193,7 @@ changes_fetch_raw(const svn_test_opts_t
struct changes_args args;
/* Create a new fs and repos */
- SVN_ERR(svn_test__create_bdb_fs(&fs, "test-repo-changes-fetch", opts,
+ SVN_ERR(svn_test__create_bdb_fs(&fs, "test-repo-changes-fetch-raw", opts,
pool));
/* First, verify that we can request changes for an arbitrary key
@@ -903,6 +903,8 @@ changes_bad_sequences(const svn_test_opt
/* The test table. */
+int svn_test_max_threads = 4;
+
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,