s3:ctdb library: fix the build against older ctdb versions
[kai/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 total, avail;
69         int ret, n;
70         bool msg = false;
71
72         if ((cfg->prefork_status & PFH_NEW_MAX) &&
73             !(cfg->prefork_status & PFH_ENOSPC)) {
74                 ret = prefork_expand_pool(pool, cfg->max_children);
75                 if (ret == ENOSPC) {
76                         cfg->prefork_status |= PFH_ENOSPC;
77                 }
78                 cfg->prefork_status &= ~PFH_NEW_MAX;
79         }
80
81         total = prefork_count_children(pool, NULL);
82         avail = prefork_count_allowed_connections(pool);
83         DEBUG(10, ("(Pre)Stats: children: %d, allowed connections: %d\n",
84                    total, avail));
85
86         if ((total < cfg->max_children) && (avail < cfg->spawn_rate)) {
87                 n = prefork_add_children(ev_ctx, msg_ctx,
88                                          pool, cfg->spawn_rate);
89                 if (n < cfg->spawn_rate) {
90                         DEBUG(10, ("Attempted to add %d children but only "
91                                    "%d were actually added!\n",
92                                    cfg->spawn_rate, n));
93                 }
94         } 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                 n = (cfg->spawn_rate / 2) + 1;
98                 if (n > cfg->spawn_rate) {
99                         n = cfg->spawn_rate;
100                 }
101                 if ((total - n) < cfg->min_children) {
102                         n = total - cfg->min_children;
103                 }
104                 if (n >= 0) {
105                         prefork_retire_children(msg_ctx, pool, n,
106                                                 now - cfg->child_min_life);
107                 }
108         }
109
110         /* total/avail may have just been changed in the above if/else */
111         total = prefork_count_children(pool, NULL);
112         avail = prefork_count_allowed_connections(pool);
113         if ((total == cfg->max_children) && (avail < cfg->spawn_rate)) {
114                 n = avail;
115                 while (avail < cfg->spawn_rate) {
116                         prefork_increase_allowed_clients(pool,
117                                                 cfg->max_allowed_clients);
118                         avail = prefork_count_allowed_connections(pool);
119                         /* if avail didn't change do not loop forever */
120                         if (n == avail) break;
121                         n = avail;
122                 }
123                 msg = true;
124         } else if (avail > total + cfg->spawn_rate) {
125                 n = avail;
126                 while (avail > total + cfg->spawn_rate) {
127                         prefork_decrease_allowed_clients(pool);
128                         avail = prefork_count_allowed_connections(pool);
129                         /* if avail didn't change do not loop forever */
130                         if (n == avail) break;
131                         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         if (msg) {
140                 prefork_warn_active_children(msg_ctx, pool);
141         }
142
143         DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
144                   prefork_count_children(pool, NULL),
145                   prefork_count_allowed_connections(pool)));
146 }
147
148 void pfh_client_terminated(struct pf_worker_data *pf)
149 {
150         if (pf->num_clients >= 0) {
151                 pf->num_clients--;
152         } else {
153                 if (pf->status != PF_WORKER_EXITING) {
154                         DEBUG(1, ("Invalid num clients, stopping!\n"));
155                 }
156                 pf->status = PF_WORKER_EXITING;
157                 pf->num_clients = -1;
158         }
159 }
160
161 bool pfh_child_allowed_to_accept(struct pf_worker_data *pf)
162 {
163         if (pf->status == PF_WORKER_EXITING ||
164             pf->status == PF_WORKER_ACCEPTING) {
165                 return false;
166         }
167
168         return (pf->num_clients < pf->allowed_clients);
169 }