Author: stefan2
Date: Sun Sep 15 18:58:49 2013
New Revision: 1523476
URL: http://svn.apache.org/r1523476
Log:
Further improve svnserve's responsiveness to large numbers of small
requests in threaded mode: Use a thread pool.
* subversion/svnserve/svnserve.c
(THREADPOOL_MIN_SIZE,
THREADPOOL_MAX_SIZE,
THREADPOOL_THREAD_IDLE_LIMIT): new tuning knobs controlling the use
of the thread pool
(main): create thread pool; use it instead of indiviual, detached threads
Modified:
subversion/trunk/subversion/svnserve/svnserve.c
Modified: subversion/trunk/subversion/svnserve/svnserve.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/svnserve.c?rev=1523476&r1=1523475&r2=1523476&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/svnserve.c (original)
+++ subversion/trunk/subversion/svnserve/svnserve.c Sun Sep 15 18:58:49 2013
@@ -30,6 +30,7 @@
#include <apr_network_io.h>
#include <apr_signal.h>
#include <apr_thread_proc.h>
+#include <apr_thread_pool.h>
#include <apr_portable.h>
#include <locale.h>
@@ -103,6 +104,41 @@ enum run_mode {
#endif
+/* Parameters for the worker thread pool used in threaded mode. */
+
+/* Have at least this many worker threads (even if there are no requests
+ * to handle).
+ *
+ * A 0 value is legal but increases the latency for the next incoming
+ * request. Higher values may be useful for servers that experience short
+ * bursts of concurrent requests followed by longer idle periods.
+ */
+#define THREADPOOL_MIN_SIZE 1
+
+/* Maximum number of worker threads. If there are more concurrent requests
+ * than worker threads, the extra requests get queued.
+ *
+ * Since very slow connections will hog a full thread for a potentially
+ * long time before timing out, be sure to not set this limit too low.
+ *
+ * On the other hand, keep in mind that every thread will allocate up to
+ * 4MB of unused RAM in the APR allocator of its root pool. 32 bit servers
+ * must hence do with fewer threads.
+ */
+#if (APR_SIZEOF_VOIDP <= 4)
+#define THREADPOOL_MAX_SIZE 64
+#else
+#define THREADPOOL_MAX_SIZE 256
+#endif
+
+/* Number of microseconds that an unused thread remains in the pool before
+ * being terminated.
+ *
+ * Higher values are useful if clients frequently send small requests and
+ * you want to minimize the latency for those.
+ */
+#define THREADPOOL_THREAD_IDLE_LIMIT 1000000
+
#ifdef WIN32
static apr_os_sock_t winservice_svnserve_accept_socket = INVALID_SOCKET;
@@ -569,8 +605,7 @@ int main(int argc, const char *argv[])
svn_ra_svn_conn_t *conn;
apr_proc_t proc;
#if APR_HAS_THREADS
- apr_threadattr_t *tattr;
- apr_thread_t *tid;
+ apr_thread_pool_t *threads;
struct shared_pool_t *shared_pool;
struct serve_thread_t *thread_data;
@@ -1107,6 +1142,29 @@ int main(int argc, const char *argv[])
if (err)
return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+#if APR_HAS_THREADS
+ if (handling_mode == connection_mode_thread)
+ {
+ /* create the thread pool */
+ status = apr_thread_pool_create(&threads,
+ THREADPOOL_MIN_SIZE,
+ THREADPOOL_MAX_SIZE,
+ pool);
+ if (status)
+ {
+ err = svn_error_wrap_apr (status, _("Can't create thread pool"));
+ return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ }
+
+ /* let idle threads linger for a while in case more requests are
+ coming in */
+ apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);
+
+ /* don't queue requests unless we reached the worker thread limit */
+ apr_thread_pool_threshold_set(threads, 0);
+ }
+#endif
+
while (1)
{
#ifdef WIN32
@@ -1216,31 +1274,16 @@ int main(int argc, const char *argv[])
little different from forking one process per connection. */
#if APR_HAS_THREADS
shared_pool = attach_shared_pool(connection_pool);
- status = apr_threadattr_create(&tattr, connection_pool);
- 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);
- }
- 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);
- }
+
thread_data = apr_palloc(connection_pool, sizeof(*thread_data));
thread_data->conn = conn;
thread_data->params = ¶ms;
thread_data->shared_pool = shared_pool;
- status = apr_thread_create(&tid, tattr, serve_thread, thread_data,
- shared_pool->pool);
+ status = apr_thread_pool_push(threads, serve_thread, thread_data,
+ 0, NULL);
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't create thread"));
+ err = svn_error_wrap_apr(status, _("Can't push task"));
svn_handle_error2(err, stderr, FALSE, "svnserve: ");
svn_error_clear(err);
exit(1);