Mercurial > dovecot > original-hg > dovecot-1.2
changeset 614:e60620644af3 HEAD
login_process_per_connection = yes scales now better when multiple users are
trying to log in at the same time.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 16 Nov 2002 07:57:20 +0200 |
parents | 1906116a62ce |
children | 0d852af6842e |
files | dovecot-example.conf src/master/login-process.c src/master/settings.c src/master/settings.h |
diffstat | 4 files changed, 60 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/dovecot-example.conf Sat Nov 16 07:21:21 2002 +0200 +++ b/dovecot-example.conf Sat Nov 16 07:57:20 2002 +0200 @@ -67,6 +67,14 @@ # yes, this is the number of extra processes waiting for users to log in. #login_processes_count = 3 +# Maximum number of extra login processes to create. The extra process count +# usually stays at login_processes_count, but when multiple users start logging +# in at the same time more extra processes are created. To prevent fork-bombing +# we check only once in a second if new processes should be created - if all +# of them are used at the time, we double their amount until limit set by this +# setting is reached. This setting is used only if login_process_per_use is yes. +#login_max_processes_count = 128 + # Maximum number of connections allowed in login state. When this limit is # reached, the oldest connections are dropped. If login_process_per_user # is no, this is a per-process value, so the absolute maximum number of users
--- a/src/master/login-process.c Sat Nov 16 07:21:21 2002 +0200 +++ b/src/master/login-process.c Sat Nov 16 07:57:20 2002 +0200 @@ -44,6 +44,7 @@ static HashTable *processes; static LoginProcess *oldest_nonlisten_process, *newest_nonlisten_process; static unsigned int listening_processes; +static unsigned int wanted_processes_count; static void login_process_destroy(LoginProcess *p); static void login_process_unref(LoginProcess *p); @@ -86,6 +87,27 @@ i_free(request); } +void login_process_mark_nonlistening(LoginProcess *p) +{ + if (!p->listening) { + i_error("login: received another \"not listening\" " + "notification"); + return; + } + + p->listening = FALSE; + listening_processes--; + + p->prev_nonlisten = newest_nonlisten_process; + + if (newest_nonlisten_process != NULL) + newest_nonlisten_process->next_nonlisten = p; + newest_nonlisten_process = p; + + if (oldest_nonlisten_process == NULL) + oldest_nonlisten_process = p; +} + static void login_process_input(void *context, int fd __attr_unused__, IO io __attr_unused__) { @@ -113,22 +135,7 @@ if (client_fd == -1) { /* just a notification that the login process isn't listening for new connections anymore */ - if (!p->listening) { - i_error("login: received another \"not listening\" " - "notification"); - } else { - p->listening = FALSE; - listening_processes--; - - p->prev_nonlisten = newest_nonlisten_process; - - if (newest_nonlisten_process != NULL) - newest_nonlisten_process->next_nonlisten = p; - newest_nonlisten_process = p; - - if (oldest_nonlisten_process == NULL) - oldest_nonlisten_process = p; - } + login_process_mark_nonlistening(p); return; } @@ -342,16 +349,39 @@ static void login_processes_start_missing(void *context __attr_unused__, Timeout timeout __attr_unused__) { - /* create max. one process every second, that way if it keeps - dying all the time we don't eat all cpu with fork()ing. */ - if (listening_processes < set_login_processes_count) - (void)create_login_process(); + if (!set_login_process_per_connection) { + /* create max. one process every second, that way if it keeps + dying all the time we don't eat all cpu with fork()ing. */ + if (listening_processes < set_login_processes_count) + (void)create_login_process(); + } else { + /* we want to respond fast when multiple clients are connecting + at once, but we also want to prevent fork-bombing. use the + same method as apache: check once a second if we need new + processes. if yes and we've used all the existing processes, + double their amount (unless we've hit the high limit). + Then for each second that didn't use all existing processes, + drop the max. process count by one. */ + if (wanted_processes_count < set_login_processes_count) + wanted_processes_count = set_login_processes_count; + else if (listening_processes == 0) + wanted_processes_count *= 2; + else if (wanted_processes_count > set_login_processes_count) + wanted_processes_count--; + + if (wanted_processes_count > set_login_max_processes_count) + wanted_processes_count = set_login_max_processes_count; + + while (listening_processes < wanted_processes_count) + (void)create_login_process(); + } } void login_processes_init(void) { auth_id_counter = 0; listening_processes = 0; + wanted_processes_count = 0; oldest_nonlisten_process = newest_nonlisten_process = NULL; processes = hash_create(default_pool, 128, NULL, NULL);
--- a/src/master/settings.c Sat Nov 16 07:21:21 2002 +0200 +++ b/src/master/settings.c Sat Nov 16 07:57:20 2002 +0200 @@ -92,6 +92,7 @@ int set_login_chroot = TRUE; int set_login_process_per_connection = TRUE; unsigned int set_login_processes_count = 3; +unsigned int set_login_max_processes_count = 128; unsigned int set_max_logging_users = 256; uid_t set_login_uid; /* generated from set_login_user */
--- a/src/master/settings.h Sat Nov 16 07:21:21 2002 +0200 +++ b/src/master/settings.h Sat Nov 16 07:57:20 2002 +0200 @@ -21,7 +21,7 @@ extern char *set_login_dir; extern int set_login_chroot; extern int set_login_process_per_connection; -extern unsigned int set_login_processes_count; +extern unsigned int set_login_processes_count, set_login_max_processes_count; extern unsigned int set_max_logging_users; extern uid_t set_login_uid;