dovecot-2.0: master: Kill extra idling processes.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Sep 9 00:49:14 EEST 2009
details: http://hg.dovecot.org/dovecot-2.0/rev/29ebf1c9ff26
changeset: 9906:29ebf1c9ff26
user: Timo Sirainen <tss at iki.fi>
date: Tue Sep 08 17:49:08 2009 -0400
description:
master: Kill extra idling processes.
diffstat:
3 files changed, 79 insertions(+), 22 deletions(-)
src/master/service-monitor.c | 97 ++++++++++++++++++++++++++++++++----------
src/master/service-process.c | 2
src/master/service-process.h | 2
diffs (155 lines):
diff -r 54c0c2c24f2c -r 29ebf1c9ff26 src/master/service-monitor.c
--- a/src/master/service-monitor.c Tue Sep 08 14:49:35 2009 -0400
+++ b/src/master/service-monitor.c Tue Sep 08 17:49:08 2009 -0400
@@ -11,13 +11,81 @@
#include "service-log.h"
#include "service-monitor.h"
+#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <syslog.h>
+#define SERVICE_PROCESS_KILL_IDLE_MSECS (1000*60)
#define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
static void service_monitor_start_extra_avail(struct service *service);
+
+static void service_process_kill_idle(struct service_process *process)
+{
+ struct service *service = process->service;
+
+ if (service->process_avail <= service->set->process_min_avail) {
+ /* we don't have any extra idling processes */
+ timeout_remove(&process->to_idle);
+ } else {
+ if (kill(process->pid, SIGINT) < 0 && errno != ESRCH) {
+ service_error(service, "kill(%s, SIGINT) failed: %m",
+ dec2str(process->pid));
+ }
+ }
+}
+
+static void service_status_more(struct service_process *process,
+ const struct master_status *status)
+{
+ struct service *service = process->service;
+
+ process->total_count +=
+ process->available_count - status->available_count;
+ process->idle_start = 0;
+
+ if (process->to_idle != NULL)
+ timeout_remove(&process->to_idle);
+
+ if (status->available_count != 0)
+ return;
+
+ /* process used up all of its clients */
+ i_assert(service->process_avail > 0);
+ service->process_avail--;
+
+ /* we may need to start more */
+ service_monitor_start_extra_avail(service);
+ service_monitor_listen_start(service);
+}
+
+static void service_status_less(struct service_process *process,
+ const struct master_status *status)
+{
+ struct service *service = process->service;
+
+ if (process->available_count == 0) {
+ /* process can accept more clients again */
+ if (service->process_avail++ == 0)
+ service_monitor_listen_stop(service);
+ i_assert(service->process_avail <= service->process_count);
+ }
+ if (status->available_count == service->client_limit) {
+ process->idle_start = ioloop_time;
+ if (service->process_avail > service->set->process_min_avail &&
+ process->to_idle == NULL) {
+ /* we have more processes than we really need.
+ add a bit of randomness so that we don't send the
+ signal to all of them at once */
+ process->to_idle =
+ timeout_add(SERVICE_PROCESS_KILL_IDLE_MSECS +
+ (rand() % 100)*10,
+ service_process_kill_idle,
+ process);
+ }
+ }
+}
static void service_status_input(struct service *service)
{
@@ -74,27 +142,11 @@ static void service_status_input(struct
return;
if (process->available_count > status.available_count) {
- /* process started servicing requests */
- process->total_count +=
- process->available_count - status.available_count;
- if (status.available_count == 0) {
- i_assert(service->process_avail > 0);
- service->process_avail--;
-
- service_monitor_start_extra_avail(service);
- service_monitor_listen_start(service);
- }
- process->idle_start = 0;
+ /* process started servicing some more clients */
+ service_status_more(process, &status);
} else {
- /* process finished servicing requests */
- if (process->available_count == 0) {
- if (service->process_avail++ == 0)
- service_monitor_listen_stop(service);
- i_assert(service->process_avail <=
- service->process_count);
- }
- if (status.available_count == service->client_limit)
- process->idle_start = ioloop_time;
+ /* process finished servicing some clients */
+ service_status_less(process, &status);
}
process->available_count = status.available_count;
}
@@ -113,10 +165,11 @@ static void service_accept(struct servic
i_assert(service->process_avail == 0);
if (service->process_count == service->process_limit) {
- /* we've reached our limits, new connections will have to
+ /* we've reached our limits, new clients will have to
wait until there are more processes available */
i_warning("service(%s): process_limit reached, "
- "connections are being dropped", service->set->name);
+ "client connections are being dropped",
+ service->set->name);
service->listen_pending = TRUE;
service_monitor_listen_stop(service);
return;
diff -r 54c0c2c24f2c -r 29ebf1c9ff26 src/master/service-process.c
--- a/src/master/service-process.c Tue Sep 08 14:49:35 2009 -0400
+++ b/src/master/service-process.c Tue Sep 08 17:49:08 2009 -0400
@@ -547,6 +547,8 @@ void service_process_destroy(struct serv
if (process->to_status != NULL)
timeout_remove(&process->to_status);
+ if (process->to_idle != NULL)
+ timeout_remove(&process->to_idle);
switch (process->service->type) {
case SERVICE_TYPE_AUTH_SERVER:
diff -r 54c0c2c24f2c -r 29ebf1c9ff26 src/master/service-process.h
--- a/src/master/service-process.h Tue Sep 08 14:49:35 2009 -0400
+++ b/src/master/service-process.h Tue Sep 08 17:49:08 2009 -0400
@@ -16,6 +16,8 @@ struct service_process {
/* time when process started idling, or 0 if we're not idling */
time_t idle_start;
+ /* kill process if it hits idle timeout */
+ struct timeout *to_idle;
/* kill the process if it doesn't send initial status notification */
struct timeout *to_status;
More information about the dovecot-cvs
mailing list