Mercurial > dovecot > core-2.2
changeset 22492:ac432c123103
director: Make sure users gets expired even on an idle director
Normally expiring gets done while looking up users, but if nothing is doing
that on an idle director the users won't get expired. This can cause confusion
in "doveadm director status" output.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 10 Aug 2017 17:50:04 +0300 |
parents | 5854337cc4ad |
children | a7af9490a266 |
files | src/director/test-user-directory.c src/director/user-directory.c |
diffstat | 2 files changed, 34 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/director/test-user-directory.c Thu Jun 08 01:03:13 2017 +0300 +++ b/src/director/test-user-directory.c Thu Aug 10 17:50:04 2017 +0300 @@ -97,6 +97,8 @@ test_user_directory_random, NULL }; - ioloop_time = 1234567890; - return test_run(test_functions); + struct ioloop *ioloop = io_loop_create(); + int ret = test_run(test_functions); + io_loop_destroy(&ioloop); + return ret; }
--- a/src/director/user-directory.c Thu Jun 08 01:03:13 2017 +0300 +++ b/src/director/user-directory.c Thu Aug 10 17:50:04 2017 +0300 @@ -12,6 +12,8 @@ /* but min/max. of this many secs */ #define USER_NEAR_EXPIRING_MIN 3 #define USER_NEAR_EXPIRING_MAX 30 +/* This shouldn't matter what it is exactly, just try it sometimes later. */ +#define USER_BEING_KILLED_EXPIRE_RETRY_SECS 60 struct user_directory_iter { struct user_directory *dir; @@ -32,6 +34,7 @@ /* If user's expire time is less than this many seconds away, don't assume that other directors haven't yet expired it */ unsigned int user_near_expiring_secs; + struct timeout *to_expire; }; static void user_move_iters(struct user_directory *dir, struct user *user) @@ -62,21 +65,28 @@ } static bool user_directory_user_has_connections(struct user_directory *dir, - struct user *user) + struct user *user, + unsigned int *retry_secs_r) { time_t expire_timestamp = user->timestamp + dir->timeout_secs; - if (expire_timestamp > ioloop_time) + if (expire_timestamp > ioloop_time) { + *retry_secs_r = expire_timestamp - ioloop_time; return TRUE; + } if (USER_IS_BEING_KILLED(user)) { /* don't free this user until the kill is finished */ + *retry_secs_r = USER_BEING_KILLED_EXPIRE_RETRY_SECS; return TRUE; } if (user->weak) { - if (expire_timestamp + USER_NEAR_EXPIRING_MAX >= ioloop_time) + if (expire_timestamp + USER_NEAR_EXPIRING_MAX >= ioloop_time) { + *retry_secs_r = expire_timestamp + + USER_NEAR_EXPIRING_MAX - ioloop_time; return TRUE; + } i_warning("User %u weakness appears to be stuck, removing it", user->username_hash); @@ -86,9 +96,17 @@ static void user_directory_drop_expired(struct user_directory *dir) { + unsigned int retry_secs = 0; + while (dir->head != NULL && - !user_directory_user_has_connections(dir, dir->head)) + !user_directory_user_has_connections(dir, dir->head, &retry_secs)) user_free(dir, dir->head); + if (dir->to_expire != NULL) + timeout_remove(&dir->to_expire); + if (retry_secs > 0) { + dir->to_expire = timeout_add(retry_secs * 1000, + user_directory_drop_expired, dir); + } } unsigned int user_directory_count(struct user_directory *dir) @@ -100,10 +118,11 @@ unsigned int username_hash) { struct user *user; + unsigned int retry_secs; user_directory_drop_expired(dir); user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash)); - if (user != NULL && !user_directory_user_has_connections(dir, user)) { + if (user != NULL && !user_directory_user_has_connections(dir, user, &retry_secs)) { user_free(dir, user); user = NULL; } @@ -188,6 +207,10 @@ } } + if (dir->to_expire == NULL) { + dir->to_expire = timeout_add(dir->timeout_secs * 1000, + user_directory_drop_expired, dir); + } dir->prev_insert_pos = user; hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user); return user; @@ -303,6 +326,8 @@ while (dir->head != NULL) user_free(dir, dir->head); + if (dir->to_expire != NULL) + timeout_remove(&dir->to_expire); hash_table_destroy(&dir->hash); array_free(&dir->iters); i_free(dir);