Original peruser doesn't do very nice graceful restarts.
1) Segfaults because server environment mismatches with children.
2) no graceful process management: all processes will be left lying around until they return (Long lost child came home). And many of them would return hours after graceful wasting resources in progress.

Server status handler will have additional table which describes the children in the GRACEFUL state. If there are none, table will be hidden

peruser graceful children status:
1 of total 163 still living
ID    PID    STATUS    TYPE
0    0    STANDBY    UNKNOWN
0    0    STANDBY    UNKNOWN
0    0    STANDBY    UNKNOWN
0    0    STANDBY    UNKNOWN
      ...
23     5958     ACTIVE     PROCESSOR
      ...
0    0    STANDBY    UNKNOWN
0    0    STANDBY    UNKNOWN

I'm running it on production server and so far thumbs up. Any fellow testers would be nice. It's getting quite ghosty here in peruser mailinglist.

Any suggestions and comments are welcome and code changes

The honor of making this (and serverLimit) patch will go to Taavi Sannik and not me. I'm just a friendly betatester, trying break as much code as possible.
--- httpd-2.2.3-clean/server/mpm/experimental/peruser/peruser.c 2007-08-15 
11:09:30.903525133 +0300
+++ httpd-2.2.3/server/mpm/experimental/peruser/peruser.c       2007-08-16 
15:33:27.927104460 +0300
@@ -264,6 +264,16 @@
 
 typedef struct
 {
+    /* identification */
+    int id;            /* index in child_info_table */
+    pid_t pid;         /* process id */
+    int status;                /* status of child */
+    int type;           /* multiplexer or processor */
+    apr_time_t last_used;
+} child_grace_info_t;
+
+typedef struct
+{
     apr_size_t num;
 } child_info_control;
 
@@ -273,7 +283,6 @@
     child_info_t *table;
 } child_info;
 
-
 typedef struct
 {
     server_env_t *senv;
@@ -293,6 +302,7 @@
  */
 static apr_size_t child_info_size;
 static child_info *child_info_image;
+static child_grace_info_t *child_grace_info_table;
 struct ap_ctable *ap_child_table;
 
 #define NUM_CHILDS (child_info_image != NULL ? child_info_image->control->num 
: 0)
@@ -355,6 +365,9 @@
 
 static int die_now = 0;
 
+int grace_children = 0;
+int grace_children_alive = 0;
+
 #ifdef GPROF
 /* 
  * change directory for gprof to plop the gmon.out file
@@ -2030,8 +2043,48 @@
         ap_update_child_status_from_indexes(i, 0, SERVER_DEAD, NULL);
       }
     }
+    
+    for(i=0;i<grace_children;i++) {
+       if (child_grace_info_table[i].pid > 0 && 
+                       apr_time_sec(now - child_grace_info_table[i].last_used) 
> expire_timeout) {
+               
+               _DBG("Killing a child from last graceful 
(pid=%d,childno=%d,last_used=%d)", 
+                               child_grace_info_table[i].pid, 
child_grace_info_table[i].id,
+                               child_grace_info_table[i].last_used);
+            
+               if(kill(child_grace_info_table[i].pid, SIGTERM) == -1)
+            {
+              ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
+                ap_server_conf, "kill SIGTERM");
+            }
+               
+               /*      We don't need to do remove_grace_child() here,
+                *  because it will be automatically done once 
+                *  the child dies by ap_mpm_run() */
+       }
+    }
 }
 
+int remove_grace_child(int slot) {
+       if (slot < grace_children) {
+               child_grace_info_table[slot].id = 0;
+               child_grace_info_table[slot].pid = 0;
+               child_grace_info_table[slot].status = CHILD_STATUS_STANDBY;
+               child_grace_info_table[slot].type = CHILD_TYPE_UNKNOWN;
+               child_grace_info_table[slot].last_used = 0;
+               grace_children_alive--;
+               
+               if (grace_children_alive <= 0) { /*     All children have 
returned from graceful        */
+                       _DBG("Every child has returned from graceful restart - 
freeing child_grace_info_table");
+                       grace_children_alive = 0;
+                       is_graceful = 0;
+                       grace_children = 0;
+                       free(child_grace_info_table);
+               }
+               return 0;
+       }
+       return 1;
+}
 
 /*****************************************************************
  * Executive routines.
@@ -2165,6 +2218,19 @@
                 mpm_state = AP_MPMQ_STOPPING;
                 return 1;
             }
+            
+            if (grace_children > 0) {
+               for(i=0;i<grace_children;i++) {
+                       if (child_grace_info_table[i].pid == pid.pid) {
+                               break;
+                       }
+               }
+               if (i != grace_children) {
+                       _DBG("Child returned from graceful (%d)", i);
+                       remove_grace_child(i);
+                       continue;
+               }
+            }
 
             /* non-fatal death... note that it's gone in the scoreboard. */
             child_slot = find_child_by_pid(&pid);
@@ -2310,9 +2376,42 @@
          * gracefully dealing with existing request.
          */
 
+        int alivechildren = 0;
+        int child_grace_info_size;
+        child_grace_info_t* old_grace_info;
+        void* mem;
+        
         for (i = 0; i < NUM_CHILDS; ++i)
         {
             ((ap_child_table[i].pid) && (ap_child_table[i].status = 
SERVER_DYING));
+            
+            if (CHILD_INFO_TABLE[i].pid) {
+               alivechildren++;
+            }
+        }
+        
+        _DBG("Initializing child_grace_info_table", 0);
+        
+        if (alivechildren > 0) {
+               if (grace_children > 0) {
+                       old_grace_info = child_grace_info_table;
+                       _DBG("%d children still living from last graceful "
+                                       "- adding to new 
child_grace_info_table", 
+                                       grace_children);
+               }
+               
+               child_grace_info_table = 
(child_grace_info_t*)calloc(alivechildren+grace_children,
+                               sizeof(child_grace_info_t));
+               
+               if (grace_children > 0) {
+                       for(i=0;i<grace_children;i++) {
+                               child_grace_info_table[i] = old_grace_info[i];
+                       }
+                       grace_children = i;
+                       free(old_grace_info);
+               }
+               else grace_children = 0;
+               
         }
 
         /* give the children the signal to die */
@@ -2324,8 +2423,19 @@
                 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
                              "write pipe_of_death");
             }
+            if (CHILD_INFO_TABLE[i].pid) {
+               child_grace_info_table[grace_children].id               = 
CHILD_INFO_TABLE[i].id;
+               child_grace_info_table[grace_children].pid              = 
CHILD_INFO_TABLE[i].pid;
+               child_grace_info_table[grace_children].status   = 
CHILD_INFO_TABLE[i].status;
+               child_grace_info_table[grace_children].type     = 
CHILD_INFO_TABLE[i].type;
+               child_grace_info_table[grace_children].last_used= 
ap_scoreboard_image->servers[i][0].last_used;
+               grace_children++;
+               grace_children_alive++;
+            }
             i++;
         }
+        _DBG("Total children of %d leaving behind for graceful restart (%d 
living)", 
+                       grace_children, grace_children_alive);
 
         for (i = 0; i < NUM_SENV; i++)
         {
@@ -2395,9 +2505,9 @@
     return OK;
 }
 
+static int restart_num = 0;
 static int peruser_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t 
*ptemp)
 {
-    static int restart_num = 0;
     int no_detach, debug, foreground, i;
     int tmp_server_limit = DEFAULT_SERVER_LIMIT;
     ap_directive_t *pdir;
@@ -2422,7 +2532,6 @@
 
     /* sigh, want this only the second time around */
     if (restart_num++ == 1) {
-       is_graceful = 0;
 
         if (!one_process && !foreground) {
             rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
@@ -2693,6 +2802,22 @@
                        );
        }
     ap_rputs("</table>\n", r);
+    
+    if (grace_children > 0) {
+       ap_rputs("<h2>peruser graceful children status</h2>\n", r);
+       ap_rprintf(r, "%d of total %d still living<br />\n", 
grace_children_alive, grace_children);
+        ap_rputs("<table border=\"0\">\n", r);
+        
ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td></tr>\n", r);
+        for (x = 0; x < grace_children; x++) {
+            ap_rprintf(r, 
"<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td></tr>\n", 
+                           child_grace_info_table[x].id, 
+                           child_grace_info_table[x].pid, 
+                           
child_status_string(child_grace_info_table[x].status), 
+                           child_type_string(child_grace_info_table[x].type)
+                           );
+        }
+        ap_rputs("</table>\n", r);
+    }
     return OK;
 }
 
_______________________________________________
Peruser mailing list
[email protected]
http://www.telana.com/mailman/listinfo/peruser

Reply via email to