diff options
Diffstat (limited to 'source3/lib/server_prefork_util.c')
-rw-r--r-- | source3/lib/server_prefork_util.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/source3/lib/server_prefork_util.c b/source3/lib/server_prefork_util.c new file mode 100644 index 0000000000..3e14015c81 --- /dev/null +++ b/source3/lib/server_prefork_util.c @@ -0,0 +1,169 @@ +/* + Unix SMB/Netbios implementation. + Prefork Helpers + Copyright (C) Simo Sorce <idra@samba.org> 2011 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/server_prefork.h" +#include "lib/server_prefork_util.h" + +void pfh_daemon_config(const char *daemon_name, + struct pf_daemon_config *cfg, + struct pf_daemon_config *default_cfg) +{ + int min, max, rate, allow, life; + + min = lp_parm_int(GLOBAL_SECTION_SNUM, + daemon_name, + "prefork_min_children", + default_cfg->min_children); + max = lp_parm_int(GLOBAL_SECTION_SNUM, + daemon_name, + "prefork_max_children", + default_cfg->max_children); + rate = lp_parm_int(GLOBAL_SECTION_SNUM, + daemon_name, + "prefork_spawn_rate", + default_cfg->spawn_rate); + allow = lp_parm_int(GLOBAL_SECTION_SNUM, + daemon_name, + "prefork_max_allowed_clients", + default_cfg->max_allowed_clients); + life = lp_parm_int(GLOBAL_SECTION_SNUM, + daemon_name, + "prefork_child_min_life", + default_cfg->child_min_life); + + if (max > cfg->max_children && cfg->max_children != 0) { + cfg->prefork_status |= PFH_NEW_MAX; + } + + cfg->min_children = min; + cfg->max_children = max; + cfg->spawn_rate = rate; + cfg->max_allowed_clients = allow; + cfg->child_min_life = life; +} + +void pfh_manage_pool(struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + struct pf_daemon_config *cfg, + struct prefork_pool *pool) +{ + time_t now = time(NULL); + int total, avail; + int ret, n; + bool msg = false; + + if ((cfg->prefork_status & PFH_NEW_MAX) && + !(cfg->prefork_status & PFH_ENOSPC)) { + ret = prefork_expand_pool(pool, cfg->max_children); + if (ret == ENOSPC) { + cfg->prefork_status |= PFH_ENOSPC; + } + cfg->prefork_status &= ~PFH_NEW_MAX; + } + + 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) && (avail < cfg->spawn_rate)) { + n = prefork_add_children(ev_ctx, msg_ctx, + pool, cfg->spawn_rate); + if (n < cfg->spawn_rate) { + DEBUG(10, ("Attempted to add %d children but only " + "%d were actually added!\n", + cfg->spawn_rate, n)); + } + } 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(msg_ctx, pool, n, + now - cfg->child_min_life); + } + } + + /* 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); + avail = prefork_count_allowed_connections(pool); + /* if avail didn't change do not loop forever */ + if (n == avail) break; + n = avail; + } + msg = true; + } else if (avail > total + cfg->spawn_rate) { + n = avail; + while (avail > total + cfg->spawn_rate) { + prefork_decrease_allowed_clients(pool); + avail = prefork_count_allowed_connections(pool); + /* if avail didn't change do not loop forever */ + if (n == avail) break; + n = avail; + } + } + + /* send message to all children when we change maximum allowed + * connections, so that they can decide to start again to listen to + * sockets if they were already topping the number of allowed + * clients. Useful only when we increase allowed clients */ + if (msg) { + prefork_warn_active_children(msg_ctx, pool); + } + + DEBUG(10, ("Stats: children: %d, allowed connections: %d\n", + prefork_count_children(pool, NULL), + prefork_count_allowed_connections(pool))); +} + +void pfh_client_terminated(struct pf_worker_data *pf) +{ + if (pf->num_clients >= 0) { + pf->num_clients--; + } else { + if (pf->status != PF_WORKER_EXITING) { + DEBUG(1, ("Invalid num clients, stopping!\n")); + } + pf->status = PF_WORKER_EXITING; + pf->num_clients = -1; + } +} + +bool pfh_child_allowed_to_accept(struct pf_worker_data *pf) +{ + if (pf->status == PF_WORKER_EXITING || + pf->status == PF_WORKER_ACCEPTING) { + return false; + } + + return (pf->num_clients < pf->allowed_clients); +} |