# HG changeset patch # User Timo Sirainen # Date 1503408752 -10800 # Node ID 3afbfedcdd31a2e2a572d4410c1b55f8a7c8b6c9 # Parent 3bf3e3364e1444a6ab5724e206f25adf83cebc32 director: Fix crash when flush is run and all backends are down. Instead of moving the users elsewhere, just kill them and flush the backend. diff -r 3bf3e3364e14 -r 3afbfedcdd31 src/director/director.c --- a/src/director/director.c Wed Sep 20 15:03:55 2017 +0300 +++ b/src/director/director.c Tue Aug 22 16:32:32 2017 +0300 @@ -984,10 +984,9 @@ director_user_move_free(user); } -static void -director_kill_user(struct director *dir, struct director_host *src, - struct user *user, struct mail_tag *tag, - struct mail_host *old_host) +void director_kill_user(struct director *dir, struct director_host *src, + struct user *user, struct mail_tag *tag, + struct mail_host *old_host) { struct director_kill_context *ctx; const char *cmd; diff -r 3bf3e3364e14 -r 3afbfedcdd31 src/director/director.h --- a/src/director/director.h Wed Sep 20 15:03:55 2017 +0300 +++ b/src/director/director.h Tue Aug 22 16:32:32 2017 +0300 @@ -201,6 +201,9 @@ struct director_connection *src_conn, struct director_host *orig_src, struct user *user) ATTR_NULL(3); +void director_kill_user(struct director *dir, struct director_host *src, + struct user *user, struct mail_tag *tag, + struct mail_host *old_host); void director_move_user(struct director *dir, struct director_host *src, struct director_host *orig_src, unsigned int username_hash, struct mail_host *host) diff -r 3bf3e3364e14 -r 3afbfedcdd31 src/director/doveadm-connection.c --- a/src/director/doveadm-connection.c Wed Sep 20 15:03:55 2017 +0300 +++ b/src/director/doveadm-connection.c Tue Aug 22 16:32:32 2017 +0300 @@ -443,6 +443,7 @@ struct director *dir = cmd->dir; struct user *user; struct mail_host *new_host; + bool users_killed = FALSE; if (dir->users_moving_count >= cmd->max_moving_users) return FALSE; @@ -456,18 +457,32 @@ while ((user = director_iterate_users_next(cmd->iter)) != NULL) { if (user->host != host) continue; + new_host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash, mail_host_get_tag(host)); if (new_host != host) T_BEGIN { - director_move_user(dir, dir->self_host, NULL, - user->username_hash, new_host); + if (new_host != NULL) { + director_move_user(dir, dir->self_host, NULL, + user->username_hash, new_host); + } else { + /* there are no more available backends. + kick the user instead. */ + director_kill_user(dir, dir->self_host, user, + user->host->tag, user->host); + users_killed = TRUE; + } } T_END; if (dir->users_moving_count >= cmd->max_moving_users) break; } if (user == NULL) director_iterate_users_deinit(&cmd->iter); + if (users_killed) { + /* no more backends. we already sent kills. now remove the + users entirely from the host. */ + director_flush_host(dir, dir->self_host, NULL, host); + } if (dir->right != NULL) director_connection_uncork(dir->right); return user == NULL;