8d7d0d2bb556f4d0f069c582e11c0abc7a2c7eea
[idra/samba.git] / source3 / lib / server_prefork_util.c
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 void pfh_daemon_config(const char *daemon_name,
25                         struct pf_daemon_config *cfg,
26                         struct pf_daemon_config *default_cfg)
27 {
28         int min, max, rate, allow, life;
29
30         min = lp_parm_int(GLOBAL_SECTION_SNUM,
31                                 daemon_name,
32                                 "prefork_min_children",
33                                 default_cfg->min_children);
34         max = lp_parm_int(GLOBAL_SECTION_SNUM,
35                                 daemon_name,
36                                 "prefork_max_children",
37                                 default_cfg->max_children);
38         rate = lp_parm_int(GLOBAL_SECTION_SNUM,
39                                 daemon_name,
40                                 "prefork_spawn_rate",
41                                 default_cfg->spawn_rate);
42         allow = lp_parm_int(GLOBAL_SECTION_SNUM,
43                                 daemon_name,
44                                 "prefork_max_allowed_clients",
45                                 default_cfg->max_allowed_clients);
46         life = lp_parm_int(GLOBAL_SECTION_SNUM,
47                                 daemon_name,
48                                 "prefork_child_min_life",
49                                 default_cfg->child_min_life);
50
51         if (max > cfg->max_children && cfg->max_children != 0) {
52                 cfg->prefork_status |= PFH_NEW_MAX;
53         }
54
55         cfg->min_children = min;
56         cfg->max_children = max;
57         cfg->spawn_rate = rate;
58         cfg->max_allowed_clients = allow;
59         cfg->child_min_life = life;
60 }
61
62 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         time_t now = time(NULL);
68         int active, total;
69         int ret, n;
70
71         if ((cfg->prefork_status & PFH_NEW_MAX) &&
72             !(cfg->prefork_status & PFH_ENOSPC)) {
73                 ret = prefork_expand_pool(pool, cfg->max_children);
74                 if (ret == ENOSPC) {
75                         cfg->prefork_status |= PFH_ENOSPC;
76                 }
77                 cfg->prefork_status &= ~PFH_NEW_MAX;
78         }
79
80         active = prefork_count_active_children(pool, &total);
81
82         if ((total < cfg->max_children) &&
83             ((total < cfg->min_children) ||
84              (total - active < cfg->spawn_rate))) {
85                 n = prefork_add_children(ev_ctx, msg_ctx,
86                                          pool, cfg->spawn_rate);
87                 if (n < cfg->spawn_rate) {
88                         DEBUG(10, ("Tried to start %d children but only,"
89                                    "%d were actually started.!\n",
90                                    cfg->spawn_rate, n));
91                 }
92         }
93
94         if (total - active > cfg->min_children) {
95                 if ((total - cfg->min_children) >= cfg->spawn_rate) {
96                         prefork_retire_children(pool, cfg->spawn_rate,
97                                                 now - cfg->child_min_life);
98                 }
99         }
100
101         n = prefork_count_allowed_connections(pool);
102         if (n <= cfg->spawn_rate) {
103                 do {
104                         prefork_increase_allowed_clients(pool,
105                                                 cfg->max_allowed_clients);
106                         n = prefork_count_allowed_connections(pool);
107                 } while (n <= cfg->spawn_rate);
108         } else if (n > cfg->max_children + cfg->spawn_rate) {
109                 do {
110                         prefork_decrease_allowed_clients(pool);
111                         n = prefork_count_allowed_connections(pool);
112                 } while (n > cfg->max_children + cfg->spawn_rate);
113         }
114
115         DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
116                   total, prefork_count_allowed_connections(pool)));
117 }
118
119 void pfh_client_terminated(struct pf_worker_data *pf)
120 {
121         if (pf->num_clients >= 0) {
122                 pf->num_clients--;
123         } else {
124                 if (pf->status != PF_WORKER_EXITING) {
125                         DEBUG(1, ("Invalid num clients, stopping!\n"));
126                 }
127                 pf->status = PF_WORKER_EXITING;
128                 pf->num_clients = -1;
129         }
130 }
131
132 bool pfh_child_allowed_to_accept(struct pf_worker_data *pf)
133 {
134         if (pf->status == PF_WORKER_EXITING ||
135             pf->status == PF_WORKER_ACCEPTING) {
136                 return false;
137         }
138
139         return (pf->num_clients < pf->allowed_clients);
140 }