]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: If time moves backwards, delay launching new processes.
authorTimo Sirainen <tss@iki.fi>
Mon, 22 Jun 2009 01:46:46 +0000 (21:46 -0400)
committerTimo Sirainen <tss@iki.fi>
Mon, 22 Jun 2009 01:46:46 +0000 (21:46 -0400)
--HG--
branch : HEAD

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

index 2001b0ca3ce98a58c76922cb074b5c3251ced095..699c76ffbc1c972f68a6e0723ea3042dbeae0a7c 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "common.h"
+#include "ioloop.h"
 #include "lib-signals.h"
 #include "fd-close-on-exec.h"
 #include "array.h"
@@ -28,6 +29,7 @@
 
 #define FATAL_FILENAME "master-fatal.lastlog"
 #define MASTER_PID_FILE_NAME "master.pid"
+#define SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS (60*3)
 
 struct master_service *master_service;
 uid_t master_uid;
@@ -418,6 +420,24 @@ static const char *get_full_config_path(struct service_list *list)
        return p_strconcat(list->pool, cwd, "/", path, NULL);
 }
 
+static void master_time_moved(time_t old_time, time_t new_time)
+{
+       unsigned long secs;
+
+       if (new_time >= old_time)
+               return;
+
+       /* time moved backwards. disable launching new service processes
+          until  */
+       secs = old_time - new_time + 1;
+       if (secs > SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS)
+               secs = SERVICE_TIME_MOVED_BACKWARDS_MAX_THROTTLE_SECS;
+       services_throttle_time_sensitives(services, secs);
+       i_warning("Time moved backwards by %lu seconds, "
+                 "waiting for %lu secs until new services are launched again.",
+                 (unsigned long)(old_time - new_time), secs);
+}
+
 static void daemonize(void)
 {
        pid_t pid;
@@ -575,6 +595,8 @@ int main(int argc, char *argv[])
                                argc, argv);
        i_set_failure_prefix("");
 
+       io_loop_set_time_moved_callback(current_ioloop, master_time_moved);
+
        master_uid = geteuid();
        master_gid = getegid();
 
index 7b6eaf003c67e0229e952c953ca27ccbea3b7cbb..6b7dd5d47948620e5ff84fd2026277b485795885 100644 (file)
 #include <sys/wait.h>
 #include <syslog.h>
 
-#define THROTTLE_TIMEOUT (1000*60)
+#define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
 
-static void service_monitor_stop(struct service *service);
-static void service_monitor_listen_start(struct service *service);
-static void service_monitor_listen_stop(struct service *service);
+void service_monitor_stop(struct service *service);
 
 static void service_status_input(struct service *service)
 {
@@ -99,22 +97,13 @@ static void service_status_input(struct service *service)
        process->available_count = status.available_count;
 }
 
-static void service_throttle_timeout(struct service *service)
-{
-       timeout_remove(&service->to_throttle);
-       service_monitor_listen_start(service);
-}
-
 static void service_monitor_throttle(struct service *service)
 {
        if (service->to_throttle != NULL)
                return;
 
        service_error(service, "command startup failed, throttling");
-       service_monitor_listen_stop(service);
-
-       service->to_throttle = timeout_add(THROTTLE_TIMEOUT,
-                                          service_throttle_timeout, service);
+       service_throttle(service, SERVICE_STARTUP_FAILURE_THROTTLE_SECS);
 }
 
 static void service_accept(struct service *service)
@@ -136,11 +125,12 @@ static void service_accept(struct service *service)
                service_monitor_listen_stop(service);
 }
 
-static void service_monitor_listen_start(struct service *service)
+void service_monitor_listen_start(struct service *service)
 {
        struct service_listener *const *listeners;
        unsigned int i, count;
 
+       service->listening = TRUE;
        service->listen_pending = FALSE;
 
        listeners = array_get(&service->listeners, &count);
@@ -152,7 +142,7 @@ static void service_monitor_listen_start(struct service *service)
        }
 }
 
-static void service_monitor_listen_stop(struct service *service)
+void service_monitor_listen_stop(struct service *service)
 {
        struct service_listener *const *listeners;
        unsigned int i, count;
@@ -164,6 +154,7 @@ static void service_monitor_listen_stop(struct service *service)
                if (l->io != NULL)
                        io_remove(&l->io);
        }
+       service->listening = FALSE;
 }
 
 void services_monitor_start(struct service_list *service_list)
@@ -202,7 +193,7 @@ void services_monitor_start(struct service_list *service_list)
                service_monitor_listen_stop(service_list->config);
 }
 
-static void service_monitor_stop(struct service *service)
+void service_monitor_stop(struct service *service)
 {
        int i;
 
index 70838a6ada8887636a48cef80cd6a0a8dac467c4..85ffb7dc98b2a2d861e56c5d39215d01497b7483 100644 (file)
@@ -10,4 +10,8 @@ void services_monitor_stop(struct service_list *service_list);
 /* Call after SIGCHLD has been detected */
 void services_monitor_reap_children(struct service_list *service_list);
 
+void service_monitor_stop(struct service *service);
+void service_monitor_listen_start(struct service *service);
+void service_monitor_listen_stop(struct service *service);
+
 #endif
index 731b6166374b2a7a01d16fc796e0b99e1071028b..9b31412a204435055f1545f8f9a514297db5c35b 100644 (file)
@@ -383,6 +383,11 @@ 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 */
+               return NULL;
+       }
+
        switch (service->type) {
        case SERVICE_TYPE_AUTH_SOURCE:
        case SERVICE_TYPE_AUTH_SERVER:
index 53a85a435639e0de54e4a8a9aceffb3866cb7171..07ccd6c3eccf9c1bfa1023126d91b022a1f9b1ee 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "common.h"
+#include "ioloop.h"
 #include "array.h"
 #include "aqueue.h"
 #include "hash.h"
@@ -421,3 +422,32 @@ void services_destroy(struct service_list *service_list)
        hash_table_destroy(&service_list->pids);
        pool_unref(&service_list->pool);
 }
+
+static void service_throttle_timeout(struct service *service)
+{
+       timeout_remove(&service->to_throttle);
+       service_monitor_listen_start(service);
+}
+
+void service_throttle(struct service *service, unsigned int secs)
+{
+       if (service->to_throttle != NULL)
+               return;
+
+       service_monitor_listen_stop(service);
+       service->to_throttle = timeout_add(secs * 1000,
+                                          service_throttle_timeout, service);
+}
+
+void services_throttle_time_sensitives(struct service_list *list,
+                                      unsigned int secs)
+{
+       struct service *const *services;
+       unsigned int i, count;
+
+       services = array_get(&list->services, &count);
+       for (i = 0; i < count; i++) {
+               if (services[i]->type == SERVICE_TYPE_UNKNOWN)
+                       service_throttle(services[i], secs);
+       }
+}
index 4267d6f3b28842dcccdfb9525cb9ef85312e99b8..a1a5a36ec3ceb93e4e16fd76dd4a3d08c3134448 100644 (file)
@@ -88,6 +88,8 @@ struct service {
 
        /* all processes are in use and new connections are coming */
        unsigned int listen_pending:1;
+       /* service is currently listening for new connections */
+       unsigned int listening:1;
 };
 
 struct service_list {
@@ -122,6 +124,12 @@ void services_destroy(struct service_list *service_list);
 /* Send a signal to all processes in a given service */
 void service_signal(struct service *service, int signo);
 
+/* Prevent service from launching new processes for a while. */
+void service_throttle(struct service *service, unsigned int secs);
+/* Time moved backwards. Throttle services that care about time. */
+void services_throttle_time_sensitives(struct service_list *list,
+                                      unsigned int secs);
+
 void service_error(struct service *service, const char *format, ...)
        ATTR_FORMAT(2, 3);