dovecot-2.0: *-login: Fixed dropping oldest connection when reac...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Sep 11 01:57:01 EEST 2009
details: http://hg.dovecot.org/dovecot-2.0/rev/77228b5431e1
changeset: 9923:77228b5431e1
user: Timo Sirainen <tss at iki.fi>
date: Thu Sep 10 18:56:49 2009 -0400
description:
*-login: Fixed dropping oldest connection when reaching all limits.
diffstat:
15 files changed, 159 insertions(+), 72 deletions(-)
src/lib-master/master-auth.c | 18 ++++++++
src/lib-master/master-interface.h | 1
src/lib-master/master-service-private.h | 5 ++
src/lib-master/master-service.c | 39 ++++++++++++------
src/lib-master/master-service.h | 5 ++
src/login-common/client-common.c | 66 ++++++++++---------------------
src/login-common/login-settings.c | 6 --
src/login-common/login-settings.h | 1
src/login-common/main.c | 14 +++++-
src/master/service-auth-source.c | 29 +++++++++++++
src/master/service-auth-source.h | 3 +
src/master/service-monitor.c | 32 ++++++++++++---
src/master/service-process.c | 7 ++-
src/master/service-process.h | 2
src/master/service.h | 3 +
diffs (truncated from 526 to 300 lines):
diff -r 2e94a44c34ff -r 77228b5431e1 src/lib-master/master-auth.c
--- a/src/lib-master/master-auth.c Thu Sep 10 18:54:14 2009 -0400
+++ b/src/lib-master/master-auth.c Thu Sep 10 18:56:49 2009 -0400
@@ -103,10 +103,28 @@ void master_auth_request_abort(struct ma
auth->free_nodes = node;
}
+static void
+master_notify_have_more_avail_processes(struct master_service *service,
+ bool have_more)
+{
+ if (!have_more) {
+ /* make sure we're listening for more connections */
+ master_service_io_listeners_add(service);
+ }
+ service->call_avail_overflow = !have_more;
+}
+
static void request_handle(struct master_auth *auth,
struct master_auth_reply *reply)
{
struct master_auth_request_node *node;
+
+ if (reply->tag == 0) {
+ /* notification from master */
+ master_notify_have_more_avail_processes(auth->service,
+ reply->status == 0);
+ return;
+ }
node = hash_table_lookup(auth->requests, POINTER_CAST(reply->tag));
if (node == NULL)
diff -r 2e94a44c34ff -r 77228b5431e1 src/lib-master/master-interface.h
--- a/src/lib-master/master-interface.h Thu Sep 10 18:54:14 2009 -0400
+++ b/src/lib-master/master-interface.h Thu Sep 10 18:56:49 2009 -0400
@@ -64,6 +64,7 @@ enum master_auth_status {
};
struct master_auth_reply {
+ /* tag=0 are notifications from master */
unsigned int tag;
enum master_auth_status status;
/* PID of the post-login mail process handling this connection */
diff -r 2e94a44c34ff -r 77228b5431e1 src/lib-master/master-service-private.h
--- a/src/lib-master/master-service-private.h Thu Sep 10 18:54:14 2009 -0400
+++ b/src/lib-master/master-service-private.h Thu Sep 10 18:56:49 2009 -0400
@@ -34,6 +34,8 @@ struct master_service {
unsigned int total_available_count;
struct master_status master_status;
+ void (*avail_overflow_callback)(void);
+
struct master_auth *auth;
master_service_connection_callback_t *callback;
@@ -46,6 +48,9 @@ struct master_service {
unsigned int initial_status_sent:1;
unsigned int default_settings:1;
unsigned int die_with_master:1;
+ unsigned int call_avail_overflow:1;
};
+void master_service_io_listeners_add(struct master_service *service);
+
#endif
diff -r 2e94a44c34ff -r 77228b5431e1 src/lib-master/master-service.c
--- a/src/lib-master/master-service.c Thu Sep 10 18:54:14 2009 -0400
+++ b/src/lib-master/master-service.c Thu Sep 10 18:56:49 2009 -0400
@@ -28,7 +28,6 @@
struct master_service *master_service;
-static void io_listeners_add(struct master_service *service);
static void io_listeners_remove(struct master_service *service);
static void master_status_update(struct master_service *service);
@@ -294,7 +293,7 @@ void master_service_init_finish(struct m
master_service_set_service_count(service, 1);
}
- io_listeners_add(service);
+ master_service_io_listeners_add(service);
if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
/* we already have a connection to be served */
@@ -380,6 +379,12 @@ unsigned int master_service_get_socket_c
return service->socket_count;
}
+void master_service_set_avail_overflow_callback(struct master_service *service,
+ void (*callback)(void))
+{
+ service->avail_overflow_callback = callback;
+}
+
const char *master_service_get_config_path(struct master_service *service)
{
return service->config_path;
@@ -433,7 +438,7 @@ void master_service_client_connection_de
void master_service_client_connection_destroyed(struct master_service *service)
{
/* we can listen again */
- io_listeners_add(service);
+ master_service_io_listeners_add(service);
i_assert(service->total_available_count > 0);
@@ -497,12 +502,20 @@ void master_service_deinit(struct master
static void master_service_listen(struct master_service_listener *l)
{
+ struct master_service *service = l->service;
struct master_service_connection conn;
- if (l->service->master_status.available_count == 0) {
- /* we are full. stop listening for now. */
- io_listeners_remove(l->service);
- return;
+ if (service->master_status.available_count == 0) {
+ /* we are full. stop listening for now, unless overflow
+ callback destroys one of the existing connections */
+ if (service->call_avail_overflow &&
+ service->avail_overflow_callback != NULL)
+ service->avail_overflow_callback();
+
+ if (service->master_status.available_count == 0) {
+ io_listeners_remove(service);
+ return;
+ }
}
memset(&conn, 0, sizeof(conn));
@@ -514,7 +527,7 @@ static void master_service_listen(struct
if (errno != ENOTSOCK) {
i_error("net_accept() failed: %m");
- master_service_error(l->service);
+ master_service_error(service);
return;
}
/* it's not a socket. probably a fifo. use the "listener"
@@ -529,10 +542,10 @@ static void master_service_listen(struct
conn.ssl = l->ssl;
net_set_nonblock(conn.fd, TRUE);
- l->service->master_status.available_count--;
- master_status_update(l->service);
-
- l->service->callback(&conn);
+ service->master_status.available_count--;
+ master_status_update(service);
+
+ service->callback(&conn);
}
static void io_listeners_init(struct master_service *service)
@@ -556,7 +569,7 @@ static void io_listeners_init(struct mas
}
}
-static void io_listeners_add(struct master_service *service)
+void master_service_io_listeners_add(struct master_service *service)
{
unsigned int i;
diff -r 2e94a44c34ff -r 77228b5431e1 src/lib-master/master-service.h
--- a/src/lib-master/master-service.h Thu Sep 10 18:54:14 2009 -0400
+++ b/src/lib-master/master-service.h Thu Sep 10 18:56:49 2009 -0400
@@ -56,6 +56,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 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. */
+void master_service_set_avail_overflow_callback(struct master_service *service,
+ void (*callback)(void));
/* Set maximum number of clients we can handle. Default is given by master. */
void master_service_set_client_limit(struct master_service *service,
diff -r 2e94a44c34ff -r 77228b5431e1 src/login-common/client-common.c
--- a/src/login-common/client-common.c Thu Sep 10 18:54:14 2009 -0400
+++ b/src/login-common/client-common.c Thu Sep 10 18:56:49 2009 -0400
@@ -19,12 +19,7 @@
#include <stdlib.h>
-/* When max. number of simultaneous connections is reached, few of the
- oldest connections are disconnected. Since we have to go through all of the
- clients, it's faster if we disconnect multiple clients. */
-#define CLIENT_DESTROY_OLDEST_COUNT 16
-
-struct client *clients = NULL;
+struct client *clients = NULL, *last_client = NULL;
static unsigned int clients_count = 0;
static void client_idle_disconnect_timeout(struct client *client)
@@ -50,12 +45,6 @@ struct client *client_create(int fd, boo
struct client *client;
i_assert(fd != -1);
-
- if (clients_get_count() >= set->login_max_connections) {
- /* reached max. users count, kill few of the
- oldest connections */
- client_destroy_oldest();
- }
/* always use nonblocking I/O */
net_set_nonblock(fd, TRUE);
@@ -80,6 +69,8 @@ struct client *client_create(int fd, boo
client->secured = ssl || client->trusted ||
net_ip_compare(remote_ip, local_ip);
+ if (last_client == NULL)
+ last_client = client;
DLLIST_PREPEND(&clients, client);
clients_count++;
@@ -114,6 +105,10 @@ void client_destroy(struct client *clien
i_assert(clients_count > 0);
clients_count--;
+ if (last_client == client) {
+ i_assert(client->prev != NULL || clients_count == 0);
+ last_client = client->prev;
+ }
DLLIST_REMOVE(&clients, client);
if (client->input != NULL)
@@ -213,39 +208,24 @@ bool client_unref(struct client *client)
void client_destroy_oldest(void)
{
- unsigned int max_connections =
- global_login_settings->login_max_connections;
struct client *client;
- struct client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
- unsigned int i, destroy_count;
-
- /* find the oldest clients and put them to destroy-buffer */
- memset(destroy_buf, 0, sizeof(destroy_buf));
-
- destroy_count = max_connections > CLIENT_DESTROY_OLDEST_COUNT*2 ?
- CLIENT_DESTROY_OLDEST_COUNT : I_MIN(max_connections/2, 1);
- for (client = clients; client != NULL; client = client->next) {
- for (i = 0; i < destroy_count; i++) {
- if (destroy_buf[i] == NULL ||
- destroy_buf[i]->created > client->created) {
- /* @UNSAFE */
- memmove(destroy_buf+i+1, destroy_buf+i,
- sizeof(destroy_buf) -
- (i+1) * sizeof(destroy_buf[0]));
- destroy_buf[i] = client;
- break;
- }
- }
- }
-
- /* then kill them */
- for (i = 0; i < destroy_count; i++) {
- if (destroy_buf[i] == NULL)
+
+ if (last_client == NULL) {
+ /* we have no clients */
+ return;
+ }
+
+ /* destroy the last client that hasn't successfully authenticated yet.
+ this is usually the last client, but don't kill it if it's just
+ waiting for master to finish its job. */
+ for (client = last_client; client != NULL; client = client->prev) {
+ if (client->master_tag == 0)
break;
-
- client_destroy(destroy_buf[i],
- "Disconnected: Connection queue full");
- }
+ }
+ if (client == NULL)
+ client = last_client;
+
+ client_destroy(client, "Disconnected: Connection queue full");
}
void clients_destroy_all(void)
diff -r 2e94a44c34ff -r 77228b5431e1 src/login-common/login-settings.c
--- a/src/login-common/login-settings.c Thu Sep 10 18:54:14 2009 -0400
+++ b/src/login-common/login-settings.c Thu Sep 10 18:56:49 2009 -0400
@@ -39,7 +39,6 @@ static struct setting_define login_setti
DEF(SET_BOOL, auth_debug),
DEF(SET_BOOL, verbose_proctitle),
- DEF(SET_UINT, login_max_connections),
DEF(SET_UINT, mail_max_userip_connections),
SETTING_DEFINE_LIST_END
@@ -70,7 +69,6 @@ static struct login_settings login_defau
MEMBER(auth_debug) FALSE,
MEMBER(verbose_proctitle) FALSE,
More information about the dovecot-cvs
mailing list