]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Added process_min_avail setting for services.
authorTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 19:44:36 +0000 (15:44 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 19:44:36 +0000 (15:44 -0400)
--HG--
branch : HEAD

src/master/master-settings.c
src/master/master-settings.h
src/master/service-monitor.c
src/master/service-process.c

index b1293262af6d49b7e09adad75cc143f4335670c8..e19c8fb00a273d5d132f3b25070e860bf6121ed3 100644 (file)
@@ -100,6 +100,7 @@ static struct setting_define service_setting_defines[] = {
 
        DEF(SET_BOOL, drop_priv_before_exec),
 
+       DEF(SET_UINT, process_min_avail),
        DEF(SET_UINT, process_limit),
        DEF(SET_UINT, client_limit),
        DEF(SET_UINT, service_count),
@@ -131,6 +132,7 @@ static struct service_settings service_default_settings = {
 
        MEMBER(drop_priv_before_exec) FALSE,
 
+       MEMBER(process_min_avail) 0,
        MEMBER(process_limit) (unsigned int)-1,
        MEMBER(client_limit) 0,
        MEMBER(service_count) 0,
@@ -285,52 +287,61 @@ master_settings_verify(void *_set, pool_t pool, const char **error_r)
        }
        services = array_get(&set->services, &count);
        for (i = 0; i < count; i++) {
-               if (*services[i]->name == '\0') {
+               struct service_settings *service = services[i];
+
+               if (*service->name == '\0') {
                        *error_r = t_strdup_printf(
                                "Service #%d is missing name", i);
                        return FALSE;
                }
-               if (*services[i]->type != '\0' &&
-                   strcmp(services[i]->type, "log") != 0 &&
-                   strcmp(services[i]->type, "config") != 0 &&
-                   strcmp(services[i]->type, "anvil") != 0 &&
-                   strcmp(services[i]->type, "auth") != 0 &&
-                   strcmp(services[i]->type, "auth-source") != 0) {
+               if (*service->type != '\0' &&
+                   strcmp(service->type, "log") != 0 &&
+                   strcmp(service->type, "config") != 0 &&
+                   strcmp(service->type, "anvil") != 0 &&
+                   strcmp(service->type, "auth") != 0 &&
+                   strcmp(service->type, "auth-source") != 0) {
                        *error_r = t_strconcat("Unknown service type: ",
-                                              services[i]->type, NULL);
+                                              service->type, NULL);
                        return FALSE;
                }
                for (j = 0; j < i; j++) {
-                       if (strcmp(services[i]->name, services[j]->name) == 0) {
+                       if (strcmp(service->name, services[j]->name) == 0) {
                                *error_r = t_strdup_printf(
                                        "Duplicate service name: %s",
-                                       services[i]->name);
+                                       service->name);
                                return FALSE;
                        }
                }
        }
        for (i = 0; i < count; i++) {
-               if (*services[i]->executable != '/') {
-                       services[i]->executable =
+               struct service_settings *service = services[i];
+
+               if (*service->executable != '/') {
+                       service->executable =
                                p_strconcat(pool, set->libexec_dir, "/",
-                                           services[i]->executable, NULL);
+                                           service->executable, NULL);
                }
-               if (*services[i]->chroot != '/' &&
-                   *services[i]->chroot != '\0') {
-                       services[i]->chroot =
+               if (*service->chroot != '/' && *service->chroot != '\0') {
+                       service->chroot =
                                p_strconcat(pool, set->base_dir, "/",
-                                           services[i]->chroot, NULL);
+                                           service->chroot, NULL);
                }
-               if (services[i]->drop_priv_before_exec &&
-                   *services[i]->chroot != '\0') {
+               if (service->drop_priv_before_exec &&
+                   *service->chroot != '\0') {
                        *error_r = t_strdup_printf("service(%s): "
                                "drop_priv_before_exec=yes can't be "
-                               "used with chroot", services[i]->name);
+                               "used with chroot", service->name);
+                       return FALSE;
+               }
+               if (service->process_min_avail > service->process_limit) {
+                       *error_r = t_strdup_printf("service(%s): "
+                               "process_min_avail is higher than process_limit",
+                               service->name);
                        return FALSE;
                }
-               fix_file_listener_paths(&services[i]->unix_listeners,
+               fix_file_listener_paths(&service->unix_listeners,
                                        pool, set->base_dir);
-               fix_file_listener_paths(&services[i]->fifo_listeners,
+               fix_file_listener_paths(&service->fifo_listeners,
                                        pool, set->base_dir);
        }
        set->protocols_split = p_strsplit(pool, set->protocols, " ");
index 3a8ac42bce0281709290050737f67b7bafc3d050..3b28b963a4cad1940744bb6bacd3bf4716ad1667 100644 (file)
@@ -31,6 +31,7 @@ struct service_settings {
 
        bool drop_priv_before_exec;
 
+       unsigned int process_min_avail;
        unsigned int process_limit;
        unsigned int client_limit;
        unsigned int service_count;
index 4704b30446918fd61094e9f22a42585a510414b1..4a174829429333d82b74171a2663838566bcee18 100644 (file)
@@ -17,7 +17,7 @@
 
 #define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
 
-void service_monitor_stop(struct service *service);
+static void service_monitor_start_extra_avail(struct service *service);
 
 static void service_status_input(struct service *service)
 {
@@ -79,8 +79,10 @@ static void service_status_input(struct service *service)
                        process->available_count - status.available_count;
                if (status.available_count == 0) {
                        i_assert(service->process_avail > 0);
-                       if (--service->process_avail == 0)
-                                service_monitor_listen_start(service);
+                       service->process_avail--;
+
+                       service_monitor_start_extra_avail(service);
+                       service_monitor_listen_start(service);
                }
                process->idle_start = 0;
        } else {
@@ -127,11 +129,37 @@ static void service_accept(struct service *service)
                service_monitor_listen_stop(service);
 }
 
+static void service_monitor_start_extra_avail(struct service *service)
+{
+       unsigned int i, count;
+
+       if (service->process_avail >= service->set->process_min_avail)
+               return;
+
+       count = service->set->process_min_avail - service->process_avail;
+       if (service->process_count + count > service->process_limit)
+               count = service->process_limit - service->process_count;
+
+       for (i = 0; i < count; i++) {
+               if (service_process_create(service, NULL, NULL) == NULL) {
+                       service_monitor_throttle(service);
+                       break;
+               }
+       }
+       if (i > 0 && service->listening) {
+               /* we created some processes, they'll do the listening now */
+               service_monitor_listen_stop(service);
+       }
+}
+
 void service_monitor_listen_start(struct service *service)
 {
        struct service_listener *const *listeners;
        unsigned int i, count;
 
+       if (service->process_avail > 0)
+               return;
+
        service->listening = TRUE;
        service->listen_pending = FALSE;
 
@@ -185,8 +213,10 @@ void services_monitor_start(struct service_list *service_list)
                                       service_status_input, services[i]);
                }
 
-               if (services[i]->status_fd[0] != -1)
+               if (services[i]->status_fd[0] != -1) {
+                       service_monitor_start_extra_avail(services[i]);
                        service_monitor_listen_start(services[i]);
+               }
        }
 
        if (service_process_create(service_list->log, NULL, NULL) != NULL)
@@ -265,8 +295,9 @@ void services_monitor_reap_children(void)
                        service_process_failure(process, status);
                }
                service_process_destroy(process);
+               service_monitor_start_extra_avail(service);
 
-                if (service->process_avail == 0 && service->to_throttle == NULL)
+                if (service->to_throttle == NULL)
                        service_monitor_listen_start(service);
        }
 }
index e5fddd9c9cc82068b3b09f225241642bdedba11d..9e4463c4831e8e63558f16ba2aacbe09e6ee498b 100644 (file)
@@ -451,8 +451,8 @@ service_process_create(struct service *service, const char *const *auth_args,
        int fd[2];
        pid_t pid;
 
-       if (!service->listening) {
-               /* probably throttling service, don't create new processes */
+       if (service->to_throttle != NULL) {
+               /* throttling service, don't create new processes */
                return NULL;
        }
        if (service->process_count >= service->process_limit) {