dovecot-2.0-sslstream: Handle shutdown_clients globally for all ...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 13 02:55:36 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0-sslstream/rev/7f0ccd367351
changeset: 10172:7f0ccd367351
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Oct 23 16:22:53 2009 -0400
description:
Handle shutdown_clients globally for all services.
Delay shutting down processes until it's convenient for them, but if they're
not gone in 30 seconds forcibly stop. And if that doesn't help, master will
start killing them in 60 seconds.

diffstat:

18 files changed, 143 insertions(+), 23 deletions(-)
src/dict/main.c                          |    6 ++++
src/imap/imap-settings.c                 |    2 -
src/imap/imap-settings.h                 |    1 
src/imap/main.c                          |   41 ++++++++++++++++++++++++++----
src/lib-master/master-service-private.h  |    3 ++
src/lib-master/master-service-settings.c |    7 ++++-
src/lib-master/master-service-settings.h |    1 
src/lib-master/master-service.c          |   28 +++++++++++++++++---
src/lib-master/master-service.h          |    5 +++
src/log/main.c                           |    4 ++
src/login-common/login-proxy.c           |   32 +++++++++++++++++++++++
src/login-common/login-proxy.h           |    2 +
src/login-common/main.c                  |    6 ++++
src/master/service.c                     |    5 ++-
src/pop3-login/client.c                  |    7 +++++
src/pop3/main.c                          |   13 +++++----
src/pop3/pop3-settings.c                 |    2 -
src/pop3/pop3-settings.h                 |    1 

diffs (truncated from 504 to 300 lines):

diff -r 47fdfd49af13 -r 7f0ccd367351 src/dict/main.c
--- a/src/dict/main.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/dict/main.c	Fri Oct 23 16:22:53 2009 -0400
@@ -14,6 +14,11 @@
 #include "dict-settings.h"
 
 static struct module *modules;
+
+static void dict_die(void)
+{
+	/* hope that other processes relying on us will die first. */
+}
 
 static void client_connected(const struct master_service_connection *conn)
 {
@@ -86,6 +91,7 @@ int main(int argc, char *argv[])
 	master_service_init_log(master_service, "dict: ");
 	main_preinit();
 	master_service_init_finish(master_service);
+	master_service_set_die_callback(master_service, dict_die);
 
 	main_init();
 	master_service_run(master_service, client_connected);
diff -r 47fdfd49af13 -r 7f0ccd367351 src/imap/imap-settings.c
--- a/src/imap/imap-settings.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/imap/imap-settings.c	Fri Oct 23 16:22:53 2009 -0400
@@ -21,7 +21,6 @@ static bool imap_settings_verify(void *_
 
 static struct setting_define imap_setting_defines[] = {
 	DEF(SET_BOOL, mail_debug),
-	DEF(SET_BOOL, shutdown_clients),
 
 	DEF(SET_UINT, imap_max_line_length),
 	DEF(SET_UINT, imap_idle_notify_interval),
@@ -36,7 +35,6 @@ static struct setting_define imap_settin
 
 static struct imap_settings imap_default_settings = {
 	MEMBER(mail_debug) FALSE,
-	MEMBER(shutdown_clients) TRUE,
 
 	/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
 	   break large message sets to multiple commands, so we're pretty
diff -r 47fdfd49af13 -r 7f0ccd367351 src/imap/imap-settings.h
--- a/src/imap/imap-settings.h	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/imap/imap-settings.h	Fri Oct 23 16:22:53 2009 -0400
@@ -13,7 +13,6 @@ enum imap_client_workarounds {
 
 struct imap_settings {
 	bool mail_debug;
-	bool shutdown_clients;
 
 	/* imap: */
 	unsigned int imap_max_line_length;
diff -r 47fdfd49af13 -r 7f0ccd367351 src/imap/main.c
--- a/src/imap/main.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/imap/main.c	Fri Oct 23 16:22:53 2009 -0400
@@ -23,10 +23,43 @@
 #define IS_STANDALONE() \
         (getenv(MASTER_UID_ENV) == NULL)
 
+#define IMAP_DIE_IDLE_SECS 10
+
 static struct mail_storage_service_ctx *storage_service;
 static struct master_login *master_login = NULL;
 
 void (*hook_client_created)(struct client **client) = NULL;
+
+static void client_kill_idle(struct client *client)
+{
+	if (client->output_lock != NULL)
+		return;
+
+	client_send_line(client, "* BYE Server shutting down.");
+	client_destroy(client, "Server shutting down.");
+}
+
+static void imap_die(void)
+{
+	struct client *client, *next;
+	time_t last_io, now = time(NULL);
+	time_t stop_timestamp = now - IMAP_DIE_IDLE_SECS;
+	unsigned int stop_msecs;
+
+	for (client = imap_clients; client != NULL; client = next) {
+		next = client->next;
+
+		last_io = I_MAX(client->last_input, client->last_output);
+		if (last_io <= stop_timestamp)
+			client_kill_idle(client);
+		else {
+			timeout_remove(&client->to_idle);
+			stop_msecs = (last_io - stop_timestamp) * 1000;
+			client->to_idle = timeout_add(stop_msecs,
+						      client_kill_idle, client);
+		}
+	}
+}
 
 static void client_add_input(struct client *client, const buffer_t *buf)
 {
@@ -94,12 +127,9 @@ client_create_from_input(const struct ma
 	if (mail_storage_service_lookup_next(storage_service, input,
 					     &user, &mail_user, error_r) <= 0)
 		return -1;
+	restrict_access_allow_coredumps(TRUE);
+
 	set = mail_storage_service_user_get_set(user)[1];
-
-	restrict_access_allow_coredumps(TRUE);
-	if (set->shutdown_clients)
-		master_service_set_die_with_master(master_service, TRUE);
-
 	client = client_create(fd_in, fd_out, mail_user, user, set);
 	T_BEGIN {
 		client_add_input(client, input_buf);
@@ -203,6 +233,7 @@ int main(int argc, char *argv[])
 	if (master_getopt(master_service) > 0)
 		return FATAL_DEFAULT;
 	master_service_init_finish(master_service);
+	master_service_set_die_callback(master_service, imap_die);
 
 	/* plugins may want to add commands, so this needs to be called early */
 	commands_init();
diff -r 47fdfd49af13 -r 7f0ccd367351 src/lib-master/master-service-private.h
--- a/src/lib-master/master-service-private.h	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/lib-master/master-service-private.h	Fri Oct 23 16:22:53 2009 -0400
@@ -35,6 +35,9 @@ struct master_service {
 	unsigned int total_available_count;
 	struct master_status master_status;
 
+	void (*die_callback)(void);
+	struct timeout *to_die;
+
 	void (*avail_overflow_callback)(void);
 	struct timeout *to_overflow_state;
 
diff -r 47fdfd49af13 -r 7f0ccd367351 src/lib-master/master-service-settings.c
--- a/src/lib-master/master-service-settings.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/lib-master/master-service-settings.c	Fri Oct 23 16:22:53 2009 -0400
@@ -31,6 +31,7 @@ static struct setting_define master_serv
 	DEF(SET_STR, log_timestamp),
 	DEF(SET_STR, syslog_facility),
 	DEF(SET_BOOL, version_ignore),
+	DEF(SET_BOOL, shutdown_clients),
 
 	SETTING_DEFINE_LIST_END
 };
@@ -41,7 +42,8 @@ static struct master_service_settings ma
 	MEMBER(debug_log_path) "",
 	MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT,
 	MEMBER(syslog_facility) "mail",
-	MEMBER(version_ignore) FALSE
+	MEMBER(version_ignore) FALSE,
+	MEMBER(shutdown_clients) TRUE
 };
 
 struct setting_parser_info master_service_setting_parser_info = {
@@ -295,6 +297,9 @@ int master_service_settings_read(struct 
 		service->version_string = NULL;
 	}
 
+	if (service->set->shutdown_clients)
+		master_service_set_die_with_master(master_service, TRUE);
+
 	/* if we change any settings afterwards, they're in expanded form.
 	   especially all settings from userdb are already expanded. */
 	settings_parse_set_expanded(service->set_parser, TRUE);
diff -r 47fdfd49af13 -r 7f0ccd367351 src/lib-master/master-service-settings.h
--- a/src/lib-master/master-service-settings.h	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/lib-master/master-service-settings.h	Fri Oct 23 16:22:53 2009 -0400
@@ -14,6 +14,7 @@ struct master_service_settings {
 	const char *log_timestamp;
 	const char *syslog_facility;
 	bool version_ignore;
+	bool shutdown_clients;
 };
 
 struct master_service_settings_input {
diff -r 47fdfd49af13 -r 7f0ccd367351 src/lib-master/master-service.c
--- a/src/lib-master/master-service.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/lib-master/master-service.c	Fri Oct 23 16:22:53 2009 -0400
@@ -32,6 +32,10 @@
    just a fallback against race conditions. */
 #define MASTER_SERVICE_STATE_CHECK_MSECS 1000
 
+/* If die callback hasn't managed to stop the service for this many seconds,
+   force it. */
+#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
+
 struct master_service *master_service;
 
 static void master_service_refresh_login_state(struct master_service *service);
@@ -219,6 +223,12 @@ void master_service_set_die_with_master(
 					bool set)
 {
 	service->die_with_master = set;
+}
+
+void master_service_set_die_callback(struct master_service *service,
+				     void (*callback)(void))
+{
+	service->die_callback = callback;
 }
 
 bool master_service_parse_option(struct master_service *service,
@@ -257,11 +267,19 @@ bool master_service_parse_option(struct 
 
 static void master_service_error(struct master_service *service)
 {
+	io_listeners_remove(service);
 	if (service->master_status.available_count ==
-	    service->total_available_count || service->die_with_master)
-		master_service_stop(service);
-	else
-		io_listeners_remove(service);
+	    service->total_available_count || service->die_with_master) {
+		if (service->die_callback == NULL)
+			master_service_stop(service);
+		else {
+			service->to_die =
+				timeout_add(MASTER_SERVICE_DIE_TIMEOUT_MSECS,
+					    master_service_stop,
+					    service);
+			service->die_callback();
+		}
+	}
 }
 
 static void master_status_error(void *context)
@@ -572,6 +590,8 @@ void master_service_deinit(struct master
 	io_listeners_remove(service);
 
 	master_service_close_config_fd(service);
+	if (service->to_die != NULL)
+		timeout_remove(&service->to_die);
 	if (service->to_overflow_state != NULL)
 		timeout_remove(&service->to_overflow_state);
 	if (service->io_status_error != NULL)
diff -r 47fdfd49af13 -r 7f0ccd367351 src/lib-master/master-service.h
--- a/src/lib-master/master-service.h	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/lib-master/master-service.h	Fri Oct 23 16:22:53 2009 -0400
@@ -65,6 +65,11 @@ void master_service_init_log(struct mast
    Normally all existing clients are handled first. */
 void master_service_set_die_with_master(struct master_service *service,
 					bool set);
+/* Call the given when master connection dies and die_with_master is TRUE.
+   The callback is expected to shut down the service somewhat soon or it's
+   done forcibly. If NULL, the service is stopped immediately. */
+void master_service_set_die_callback(struct master_service *service,
+				     void (*callback)(void));
 /* Call the given callback when there are no available connections and master
    has indicated that it can't create any more processes to handle requests.
    The callback could decide to kill one of the existing connections. */
diff -r 47fdfd49af13 -r 7f0ccd367351 src/log/main.c
--- a/src/log/main.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/log/main.c	Fri Oct 23 16:22:53 2009 -0400
@@ -54,6 +54,10 @@ int main(int argc, char *argv[])
 
 	master_service_init_log(master_service, "log: ");
 	master_service_init_finish(master_service);
+
+	/* logging should never die if there are some clients */
+	master_service_set_die_with_master(master_service, FALSE);
+
 	main_init();
 	master_service_run(master_service, client_connected);
 	main_deinit();
diff -r 47fdfd49af13 -r 7f0ccd367351 src/login-common/login-proxy.c
--- a/src/login-common/login-proxy.c	Fri Oct 23 16:19:34 2009 -0400
+++ b/src/login-common/login-proxy.c	Fri Oct 23 16:22:53 2009 -0400
@@ -15,6 +15,7 @@
 
 #define MAX_PROXY_INPUT_SIZE 4096
 #define OUTBUF_THRESHOLD 1024
+#define LOGIN_PROXY_DIE_IDLE_SECS 2
 
 struct login_proxy {
 	struct login_proxy *prev, *next;
@@ -25,6 +26,7 @@ struct login_proxy {
 	struct istream *server_input;
 	struct ostream *client_output, *server_output;
 	struct ssl_proxy *ssl_server_proxy;
+	time_t last_io;
 
 	struct timeval created;
 	struct timeout *to;
@@ -49,6 +51,7 @@ static void server_input(struct login_pr
 	unsigned char buf[OUTBUF_THRESHOLD];
 	ssize_t ret;
 
+	proxy->last_io = ioloop_time;
 	if (o_stream_get_buffer_used_size(proxy->client_output) >
 	    OUTBUF_THRESHOLD) {
 		/* client's output buffer is already quite full.
@@ -67,6 +70,7 @@ static void proxy_client_input(struct lo
 	unsigned char buf[OUTBUF_THRESHOLD];
 	ssize_t ret;
 
+	proxy->last_io = ioloop_time;
 	if (o_stream_get_buffer_used_size(proxy->server_output) >


More information about the dovecot-cvs mailing list