dovecot-2.2: master: Pre-fork processes only while master doesn'...

dovecot at dovecot.org dovecot at dovecot.org
Mon Sep 2 17:37:58 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/a3f0aca52d6f
changeset: 16705:a3f0aca52d6f
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Sep 02 17:37:47 2013 +0300
description:
master: Pre-fork processes only while master doesn't have more important things to do.

diffstat:

 src/master/service-monitor.c |  54 +++++++++++++++++++++++++++++++++++++++----
 src/master/service-process.c |   1 +
 src/master/service.h         |   5 ++++
 3 files changed, 55 insertions(+), 5 deletions(-)

diffs (139 lines):

diff -r a4bfccbc2477 -r a3f0aca52d6f src/master/service-monitor.c
--- a/src/master/service-monitor.c	Mon Sep 02 17:06:49 2013 +0300
+++ b/src/master/service-monitor.c	Mon Sep 02 17:37:47 2013 +0300
@@ -24,6 +24,7 @@
 #define SERVICE_DROP_TIMEOUT_MSECS (10*1000)
 #define MAX_DIE_WAIT_SECS 5
 #define SERVICE_MAX_EXIT_FAILURES_IN_SEC 10
+#define SERVICE_PREFORK_MAX_AT_ONCE 10
 
 static void service_monitor_start_extra_avail(struct service *service);
 static void service_status_more(struct service_process *process,
@@ -81,7 +82,7 @@
 	    service->process_count == service->process_limit)
 		service_login_notify(service, TRUE);
 
-	/* we may need to start more  */
+	/* we may need to start more */
 	service_monitor_start_extra_avail(service);
 	service_monitor_listen_start(service);
 }
@@ -302,17 +303,18 @@
 		service_monitor_listen_stop(service);
 }
 
-static void service_monitor_start_extra_avail(struct service *service)
+static bool
+service_monitor_start_count(struct service *service, unsigned int limit)
 {
 	unsigned int i, count;
 
-	if (service->process_avail >= service->set->process_min_avail ||
-	    service->list->destroying)
-		return;
+	i_assert(service->set->process_min_avail >= service->process_avail);
 
 	count = service->set->process_min_avail - service->process_avail;
 	if (service->process_count + count > service->process_limit)
 		count = service->process_limit - service->process_count;
+	if (count > limit)
+		count = limit;
 
 	for (i = 0; i < count; i++) {
 		if (service_process_create(service) == NULL) {
@@ -324,6 +326,44 @@
 		/* we created some processes, they'll do the listening now */
 		service_monitor_listen_stop(service);
 	}
+	return i == count;
+}
+
+static void service_monitor_prefork_timeout(struct service *service)
+{
+	/* don't prefork more processes if other more important processes had
+	   been forked while we were waiting for this timeout (= master seems
+	   busy) */
+	if (service->list->fork_counter != service->prefork_counter) {
+		service->prefork_counter = service->list->fork_counter;
+		return;
+	}
+	if (service->process_avail < service->set->process_min_avail) {
+		if (service_monitor_start_count(service, SERVICE_PREFORK_MAX_AT_ONCE) &&
+		    service->process_avail < service->set->process_min_avail)
+			return;
+	}
+	timeout_remove(&service->to_prefork);
+}
+
+static void service_monitor_start_extra_avail(struct service *service)
+{
+	if (service->process_avail >= service->set->process_min_avail ||
+	    service->list->destroying)
+		return;
+
+	if (service->process_avail == 0) {
+		/* quickly start one process now */
+		if (!service_monitor_start_count(service, 1))
+			return;
+		if (service->process_avail >= service->set->process_min_avail)
+			return;
+	}
+	if (service->to_prefork == NULL) {
+		service->prefork_counter = service->list->fork_counter;
+		service->to_prefork =
+			timeout_add_short(0, service_monitor_prefork_timeout, service);
+	}
 }
 
 static void service_monitor_listen_start_force(struct service *service)
@@ -491,6 +531,8 @@
 
 	if (service->to_throttle != NULL)
 		timeout_remove(&service->to_throttle);
+	if (service->to_prefork != NULL)
+		timeout_remove(&service->to_prefork);
 }
 
 static void services_monitor_wait(struct service_list *service_list)
@@ -610,6 +652,8 @@
 		service_stopped = service->status_fd[0] == -1;
 		if (!service_stopped) {
 			service_monitor_start_extra_avail(service);
+			/* if there are no longer listening processes,
+			   start listening for more */
 			if (service->to_throttle == NULL)
 				service_monitor_listen_start(service);
 		}
diff -r a4bfccbc2477 -r a3f0aca52d6f src/master/service-process.c
--- a/src/master/service-process.c	Mon Sep 02 17:06:49 2013 +0300
+++ b/src/master/service-process.c	Mon Sep 02 17:37:47 2013 +0300
@@ -295,6 +295,7 @@
 	} else {
 		pid = fork();
 		process_forked = TRUE;
+		service->list->fork_counter++;
 	}
 
 	if (pid < 0) {
diff -r a4bfccbc2477 -r a3f0aca52d6f src/master/service.h
--- a/src/master/service.h	Mon Sep 02 17:06:49 2013 +0300
+++ b/src/master/service.h	Mon Sep 02 17:37:47 2013 +0300
@@ -100,6 +100,10 @@
 	   start dropping pending connections */
 	struct timeout *to_drop;
 
+	/* prefork processes up to process_min_avail if there's time */
+	struct timeout *to_prefork;
+	unsigned int prefork_counter;
+
 	/* Last time a "dropping client connections" warning was logged */
 	time_t last_drop_warning;
 
@@ -120,6 +124,7 @@
 	pool_t set_pool;
 	int refcount;
 	struct timeout *to_kill;
+	unsigned int fork_counter;
 
 	const struct master_settings *set;
 	const struct master_service_settings *service_set;


More information about the dovecot-cvs mailing list