s3-prefork: Improve heuristics
authorSimo Sorce <idra@samba.org>
Tue, 16 Aug 2011 22:20:51 +0000 (18:20 -0400)
committerSimo Sorce <idra@samba.org>
Sun, 21 Aug 2011 13:05:05 +0000 (09:05 -0400)
Signed-off-by: Andreas Schneider <asn@samba.org>
Signed-off-by: Simo Sorce <idra@samba.org>
source3/lib/server_prefork.c
source3/lib/server_prefork.h
source3/lib/server_prefork_util.c

index 71441c3303bbea0eaef1577ec2e33a675718d1b2..d63e6a1673874690d83affe3c3a72ebe09a05ff6 100644 (file)
@@ -279,7 +279,7 @@ int prefork_retire_children(struct prefork_pool *pfp,
        return j;
 }
 
-int prefork_count_active_children(struct prefork_pool *pfp, int *total)
+int prefork_count_children(struct prefork_pool *pfp, int *active)
 {
        int i, a, t;
 
@@ -292,15 +292,18 @@ int prefork_count_active_children(struct prefork_pool *pfp, int *total)
 
                t++;
 
-               if (pfp->pool[i].num_clients <= 0) {
+               if ((pfp->pool[i].status == PF_WORKER_EXITING) ||
+                   (pfp->pool[i].num_clients <= 0)) {
                        continue;
                }
 
                a++;
        }
 
-       *total = t;
-       return a;
+       if (active) {
+               *active = a;
+       }
+       return t;
 }
 
 static void prefork_cleanup_loop(struct prefork_pool *pfp)
index 334b5813a00e7d1496251390f8ba8e4f2bc46567..d240641a39325d211cedd4d13e6fcfb5ffad1e05 100644 (file)
@@ -168,14 +168,14 @@ int prefork_add_children(struct tevent_context *ev_ctx,
 int prefork_retire_children(struct prefork_pool *pfp,
                            int num_children, time_t age_limit);
 /**
-* @brief Count the number of active children
+* @brief Count the number of children
 *
 * @param pfp   The pool.
-* @param total Returns the number of children currently alive
+* @param active        Number of children currently active if not NULL
 *
-* @return The number of children actually serving clients
+* @return The total number of children.
 */
-int prefork_count_active_children(struct prefork_pool *pfp, int *total);
+int prefork_count_children(struct prefork_pool *pfp, int *active);
 
 /**
 * @brief Count the number of actual connections currently allowed
index 8d7d0d2bb556f4d0f069c582e11c0abc7a2c7eea..638ce66f094bc0b3696541035e6e67475b104a51 100644 (file)
@@ -65,7 +65,7 @@ void pfh_manage_pool(struct tevent_context *ev_ctx,
                     struct prefork_pool *pool)
 {
        time_t now = time(NULL);
-       int active, total;
+       int total, avail;
        int ret, n;
 
        if ((cfg->prefork_status & PFH_NEW_MAX) &&
@@ -77,43 +77,62 @@ void pfh_manage_pool(struct tevent_context *ev_ctx,
                cfg->prefork_status &= ~PFH_NEW_MAX;
        }
 
-       active = prefork_count_active_children(pool, &total);
+       total = prefork_count_children(pool, NULL);
+       avail = prefork_count_allowed_connections(pool);
+       DEBUG(10, ("(Pre)Stats: children: %d, allowed connections: %d\n",
+                  total, avail));
 
-       if ((total < cfg->max_children) &&
-           ((total < cfg->min_children) ||
-            (total - active < cfg->spawn_rate))) {
+       if ((total < cfg->max_children) && (avail < cfg->spawn_rate)) {
                n = prefork_add_children(ev_ctx, msg_ctx,
                                         pool, cfg->spawn_rate);
                if (n < cfg->spawn_rate) {
-                       DEBUG(10, ("Tried to start %d children but only,"
-                                  "%d were actually started.!\n",
+                       DEBUG(10, ("Attempted to add %d children but only "
+                                  "%d were actually added!\n",
                                   cfg->spawn_rate, n));
                }
-       }
-
-       if (total - active > cfg->min_children) {
-               if ((total - cfg->min_children) >= cfg->spawn_rate) {
-                       prefork_retire_children(pool, cfg->spawn_rate,
+       } else if ((avail - cfg->min_children) >= cfg->spawn_rate) {
+               /* be a little slower in retiring children, to allow for
+                * double spikes of traffic to be handled more gracefully */
+               n = (cfg->spawn_rate / 2) + 1;
+               if (n > cfg->spawn_rate) {
+                       n = cfg->spawn_rate;
+               }
+               if ((total - n) < cfg->min_children) {
+                       n = total - cfg->min_children;
+               }
+               if (n >= 0) {
+                       prefork_retire_children(pool, n,
                                                now - cfg->child_min_life);
                }
        }
 
-       n = prefork_count_allowed_connections(pool);
-       if (n <= cfg->spawn_rate) {
-               do {
+       /* total/avail may have just been changed in the above if/else */
+       total = prefork_count_children(pool, NULL);
+       avail = prefork_count_allowed_connections(pool);
+       if ((total == cfg->max_children) && (avail < cfg->spawn_rate)) {
+               n = avail;
+               while (avail < cfg->spawn_rate) {
                        prefork_increase_allowed_clients(pool,
                                                cfg->max_allowed_clients);
-                       n = prefork_count_allowed_connections(pool);
-               } while (n <= cfg->spawn_rate);
-       } else if (n > cfg->max_children + cfg->spawn_rate) {
-               do {
+                       avail = prefork_count_allowed_connections(pool);
+                       /* if avail didn't change do not loop forever */
+                       if (n == avail) break;
+                       n = avail;
+               }
+       } else if (avail > total + cfg->spawn_rate) {
+               n = avail;
+               while (avail > total + cfg->spawn_rate) {
                        prefork_decrease_allowed_clients(pool);
-                       n = prefork_count_allowed_connections(pool);
-               } while (n > cfg->max_children + cfg->spawn_rate);
+                       avail = prefork_count_allowed_connections(pool);
+                       /* if avail didn't change do not loop forever */
+                       if (n == avail) break;
+                       n = avail;
+               }
        }
 
        DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
-                 total, prefork_count_allowed_connections(pool)));
+                 prefork_count_children(pool, NULL),
+                 prefork_count_allowed_connections(pool)));
 }
 
 void pfh_client_terminated(struct pf_worker_data *pf)