Line data Source code
1 : /*
2 : Unix SMB/Netbios implementation.
3 : Prefork Helpers
4 : Copyright (C) Simo Sorce <idra@samba.org> 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "lib/server_prefork.h"
22 : #include "lib/server_prefork_util.h"
23 :
24 63 : void pfh_daemon_config(const char *daemon_name,
25 : struct pf_daemon_config *cfg,
26 : const struct pf_daemon_config *default_cfg)
27 : {
28 : int min, max, rate, allow, life;
29 :
30 63 : min = lp_parm_int(GLOBAL_SECTION_SNUM,
31 : daemon_name,
32 : "prefork_min_children",
33 0 : default_cfg->min_children);
34 63 : max = lp_parm_int(GLOBAL_SECTION_SNUM,
35 : daemon_name,
36 : "prefork_max_children",
37 0 : default_cfg->max_children);
38 63 : rate = lp_parm_int(GLOBAL_SECTION_SNUM,
39 : daemon_name,
40 : "prefork_spawn_rate",
41 0 : default_cfg->spawn_rate);
42 63 : allow = lp_parm_int(GLOBAL_SECTION_SNUM,
43 : daemon_name,
44 : "prefork_max_allowed_clients",
45 0 : default_cfg->max_allowed_clients);
46 63 : life = lp_parm_int(GLOBAL_SECTION_SNUM,
47 : daemon_name,
48 : "prefork_child_min_life",
49 0 : default_cfg->child_min_life);
50 :
51 63 : if (max > cfg->max_children && cfg->max_children != 0) {
52 0 : cfg->prefork_status |= PFH_NEW_MAX;
53 : }
54 :
55 63 : cfg->min_children = min;
56 63 : cfg->max_children = max;
57 63 : cfg->spawn_rate = rate;
58 63 : cfg->max_allowed_clients = allow;
59 63 : cfg->child_min_life = life;
60 63 : }
61 :
62 2900 : void pfh_manage_pool(struct tevent_context *ev_ctx,
63 : struct messaging_context *msg_ctx,
64 : struct pf_daemon_config *cfg,
65 : struct prefork_pool *pool)
66 : {
67 2900 : time_t now = time(NULL);
68 : int total, avail;
69 : int ret, n;
70 2900 : bool msg = false;
71 :
72 2900 : if ((cfg->prefork_status & PFH_NEW_MAX) &&
73 0 : !(cfg->prefork_status & PFH_ENOSPC)) {
74 0 : ret = prefork_expand_pool(pool, cfg->max_children);
75 0 : if (ret == ENOSPC) {
76 0 : cfg->prefork_status |= PFH_ENOSPC;
77 : }
78 0 : cfg->prefork_status &= ~PFH_NEW_MAX;
79 : }
80 :
81 2900 : total = prefork_count_children(pool, NULL);
82 2900 : avail = prefork_count_allowed_connections(pool);
83 2900 : DEBUG(10, ("(Pre)Stats: children: %d, allowed connections: %d\n",
84 : total, avail));
85 :
86 2900 : if ((total < cfg->max_children) && (avail < cfg->spawn_rate)) {
87 21 : n = prefork_add_children(ev_ctx, msg_ctx,
88 : pool, cfg->spawn_rate);
89 12 : if (n < cfg->spawn_rate) {
90 0 : DEBUG(10, ("Attempted to add %d children but only "
91 : "%d were actually added!\n",
92 : cfg->spawn_rate, n));
93 : }
94 2879 : } else if ((avail - cfg->min_children) >= cfg->spawn_rate) {
95 : /* be a little slower in retiring children, to allow for
96 : * double spikes of traffic to be handled more gracefully */
97 72 : n = (cfg->spawn_rate / 2) + 1;
98 72 : if (n > cfg->spawn_rate) {
99 0 : n = cfg->spawn_rate;
100 : }
101 72 : if ((total - n) < cfg->min_children) {
102 0 : n = total - cfg->min_children;
103 : }
104 72 : if (n >= 0) {
105 72 : prefork_retire_children(msg_ctx, pool, n,
106 72 : now - cfg->child_min_life);
107 : }
108 : }
109 :
110 : /* total/avail may have just been changed in the above if/else */
111 2885 : total = prefork_count_children(pool, NULL);
112 2885 : avail = prefork_count_allowed_connections(pool);
113 2885 : if ((total == cfg->max_children) && (avail < cfg->spawn_rate)) {
114 0 : n = avail;
115 0 : while (avail < cfg->spawn_rate) {
116 0 : prefork_increase_allowed_clients(pool,
117 : cfg->max_allowed_clients);
118 0 : avail = prefork_count_allowed_connections(pool);
119 : /* if avail didn't change do not loop forever */
120 0 : if (n == avail) break;
121 0 : n = avail;
122 : }
123 0 : msg = true;
124 2885 : } else if (avail > total + cfg->spawn_rate) {
125 0 : n = avail;
126 0 : while (avail > total + cfg->spawn_rate) {
127 0 : prefork_decrease_allowed_clients(pool);
128 0 : avail = prefork_count_allowed_connections(pool);
129 : /* if avail didn't change do not loop forever */
130 0 : if (n == avail) break;
131 0 : n = avail;
132 : }
133 : }
134 :
135 : /* send message to all children when we change maximum allowed
136 : * connections, so that they can decide to start again to listen to
137 : * sockets if they were already topping the number of allowed
138 : * clients. Useful only when we increase allowed clients */
139 2885 : if (msg) {
140 0 : prefork_warn_active_children(msg_ctx, pool);
141 : }
142 :
143 2885 : DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
144 : prefork_count_children(pool, NULL),
145 : prefork_count_allowed_connections(pool)));
146 2885 : }
147 :
148 1002 : void pfh_client_terminated(struct pf_worker_data *pf)
149 : {
150 1002 : if (pf->num_clients >= 0) {
151 1002 : pf->num_clients--;
152 : } else {
153 0 : if (pf->status != PF_WORKER_EXITING) {
154 0 : DEBUG(1, ("Invalid num clients, stopping!\n"));
155 : }
156 0 : pf->status = PF_WORKER_EXITING;
157 0 : pf->num_clients = -1;
158 : }
159 1002 : }
160 :
161 168432 : bool pfh_child_allowed_to_accept(struct pf_worker_data *pf)
162 : {
163 336864 : if (pf->status == PF_WORKER_EXITING ||
164 168432 : pf->status == PF_WORKER_ACCEPTING) {
165 34377 : return false;
166 : }
167 :
168 134055 : return (pf->num_clients < pf->allowed_clients);
169 : }
|