This patch implements a resource pool of context pools -- a queue of
available pools that the listener thread can pull from when accepting
a request. The worker thread that picks up that request then uses
that pool for the lifetime of that transaction, clear()ing the pool
and releasing it back to what I'm calling the "pool_queue" (har har).
This replaces the prior implementation that would create and destroy
a transaction pool for each and every request.

I'm seeing a small performance improvement with this patch, but I suspect
the fd_queue code could be improved for better parallelism. I also
suspect that with better testing this algorithm may prove more scalable.

-aaron


Index: worker.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.17
diff -u -r1.17 worker.c
--- worker.c    2001/08/26 01:24:41     1.17
+++ worker.c    2001/08/28 00:00:03
@@ -125,6 +125,7 @@
 static int num_listensocks = 0;
 static apr_socket_t **listensocks;
 static fd_queue_t *worker_queue;
+static fd_queue_t *pool_queue; /* a resource pool of context pools */
 
 /* The structure used to pass unique initialization info to each thread */
 typedef struct {
@@ -203,6 +204,7 @@
     /* XXX: This will happen naturally on a graceful, and we don't care otherwise.
     ap_queue_signal_all_wakeup(worker_queue); */
     ap_queue_interrupt_all(worker_queue);
+    ap_queue_interrupt_all(pool_queue);
 }
 
 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
@@ -556,6 +558,7 @@
     int thread_slot = ti->tid;
     apr_pool_t *tpool = apr_thread_pool_get(thd);
     apr_socket_t *csd = NULL;
+    apr_socket_t *dummycsd = NULL;
     apr_pool_t *ptrans;                /* Pool for per-transaction stuff */
     apr_socket_t *sd = NULL;
     int n;
@@ -641,9 +644,20 @@
         }
     got_fd:
         if (!workers_may_exit) {
-            /* create a new transaction pool for each accepted socket */
-            apr_pool_create(&ptrans, tpool);
 
+            /* pull the next available transaction pool from the queue */
+            if ((rv = ap_queue_pop(pool_queue, &dummycsd, &ptrans))
+                != FD_QUEUE_SUCCESS) {
+                if (rv == FD_QUEUE_EINTR) {
+                    goto got_fd;
+                }
+                else { /* got some error in the queue */
+                    csd = NULL;
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, 
+                        "ap_queue_pop");
+                }
+            }
+
             if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) {
                 csd = NULL;
                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, 
@@ -678,9 +692,7 @@
     ap_scoreboard_image->parent[process_slot].quiescing = 1;
     kill(ap_my_pid, SIGTERM);
 
-/* this is uncommented when we make a pool-pool
     apr_thread_exit(thd, APR_SUCCESS);
-*/
     return NULL;
 }
 
@@ -695,8 +707,6 @@
 
     free(ti);
 
-    /* apr_pool_create(&ptrans, tpool); */
-
     while (!workers_may_exit) {
         rv = ap_queue_pop(worker_queue, &csd, &ptrans);
         /* We get FD_QUEUE_EINTR whenever ap_queue_pop() has been interrupted
@@ -708,11 +718,16 @@
         }
         process_socket(ptrans, csd, process_slot, thread_slot);
         requests_this_child--; /* FIXME: should be synchronized - aaron */
-        apr_pool_destroy(ptrans);
+
+        /* get this transaction pool ready for the next request */
+        apr_pool_clear(ptrans);
+        /* don't bother checking if we were interrupted in ap_queue_push,
+         * because we're going to check workers_may_exit right now anyway. */
+        ap_queue_push(pool_queue, NULL, ptrans);
     }
 
-    ap_update_child_status(process_slot, thread_slot, (dying) ? SERVER_DEAD : 
SERVER_GRACEFUL,
-        (request_rec *) NULL);
+    ap_update_child_status(process_slot, thread_slot,
+        (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);
     apr_lock_acquire(worker_thread_count_mutex);
     worker_thread_count--;
     apr_lock_release(worker_thread_count_mutex);
@@ -731,7 +746,7 @@
     return 0;
 }
 
-static void *start_threads(apr_thread_t *thd, void * dummy)
+static void *start_threads(apr_thread_t *thd, void *dummy)
 {
     thread_starter *ts = dummy;
     apr_thread_t **threads = ts->threads;
@@ -743,12 +758,24 @@
     int i = 0;
     int threads_created = 0;
     apr_thread_t *listener;
+    apr_pool_t *ptrans;
+    apr_socket_t *dummycsd = NULL;
 
-    /* We must create the fd queue before we start up the listener
+    /* We must create the fd queues before we start up the listener
      * and worker threads. */
-    worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
+    worker_queue = apr_pcalloc(pchild, sizeof(fd_queue_t));
     ap_queue_init(worker_queue, ap_threads_per_child, pchild);
 
+    /* create the resource pool of available transaction pools */
+    pool_queue = apr_pcalloc(pchild, sizeof(fd_queue_t));
+    ap_queue_init(pool_queue, ap_threads_per_child, pchild);
+    /* fill the pool_queue with real pools */
+    for (i = 0; i < ap_threads_per_child; i++) {
+        ptrans = NULL;
+        apr_pool_create(&ptrans, pchild);
+        ap_queue_push(pool_queue, dummycsd, ptrans);
+    }
+
     my_info = (proc_info *)malloc(sizeof(proc_info));
     my_info->pid = my_child_num;
     my_info->tid = i;
@@ -838,7 +865,7 @@
 
     ap_run_child_init(pchild, ap_server_conf);
 
-    /*done with init critical section */
+    /* done with init critical section */
 
     rv = apr_setup_signal_thread();
     if (rv != APR_SUCCESS) {

Reply via email to