Mercurial > dovecot > core-2.2
changeset 21079:d6f399a7f672
director: Keep per-tag directory
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Thu, 20 Oct 2016 19:06:22 +0300 |
parents | 6d37f4dd198d |
children | cff03c8c420f |
files | src/director/director-connection.c src/director/director-request.c src/director/director.c src/director/director.h src/director/doveadm-connection.c src/director/mail-host.c src/director/mail-host.h src/director/main.c src/director/notify-connection.c |
diffstat | 9 files changed, 180 insertions(+), 70 deletions(-) [+] |
line wrap: on
line diff
--- a/src/director/director-connection.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/director-connection.c Thu Oct 20 19:06:22 2016 +0300 @@ -502,7 +502,7 @@ struct director *dir = conn->dir; struct user *user; bool ret = FALSE, unset_weak_user = FALSE; - struct user_directory *users = dir->users; + struct user_directory *users = host->tag->users; *forced_r = FALSE; @@ -1236,7 +1236,7 @@ if (conn->users_unsorted && conn->user_iter == NULL) { /* we sent our user list before receiving remote's */ conn->users_unsorted = FALSE; - user_directory_sort(conn->dir->users); + mail_hosts_sort_users(conn->dir->mail_hosts); } str = t_str_new(128); @@ -1906,7 +1906,7 @@ if (conn->users_unsorted && conn->handshake_received) { /* we received remote's list of users before sending ours */ conn->users_unsorted = FALSE; - user_directory_sort(conn->dir->users); + mail_hosts_sort_users(conn->dir->mail_hosts); } ret = o_stream_flush(conn->output);
--- a/src/director/director-request.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/director-request.c Thu Oct 20 19:06:22 2016 +0300 @@ -96,8 +96,12 @@ DIRECTOR_REQUEST_TIMEOUT_SECS > ioloop_time) break; - user = user_directory_lookup(request->dir->users, - request->username_hash); + const char *tag_name = request->username_tag == NULL ? "" : + request->username_tag; + struct mail_tag *tag = mail_tag_find(dir->mail_hosts, tag_name); + user = tag == NULL ? NULL : + user_directory_lookup(tag->users, request->username_hash); + errormsg = director_request_get_timeout_error(request, user, str); if (user != NULL && @@ -172,11 +176,9 @@ } static bool -director_request_existing(struct director_request *request, struct user *user, - const char *tag) +director_request_existing(struct director_request *request, struct user *user) { struct director *dir = request->dir; - struct user_directory *users = dir->users; struct mail_host *host; if (USER_IS_BEING_KILLED(user)) { @@ -203,12 +205,13 @@ request->username_hash); return FALSE; } - if (!user_directory_user_is_near_expiring(users, user)) + if (!user_directory_user_is_near_expiring(user->host->tag->users, user)) return TRUE; /* user is close to being expired. another director may have already expired it. */ - host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash, tag); + host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash, + user->host->tag->name); if (!dir->ring_synced) { /* try again later once ring is synced */ request->delay_reason = REQUEST_DELAY_RINGNOTSYNCED; @@ -267,10 +270,10 @@ bool director_request_continue(struct director_request *request) { struct director *dir = request->dir; - struct user_directory *users = dir->users; struct mail_host *host; struct user *user; const char *tag; + struct mail_tag *mail_tag; if (!dir->ring_handshaked) { /* delay requests until ring handshaking is complete */ @@ -281,12 +284,16 @@ return FALSE; } - user = user_directory_lookup(users, request->username_hash); tag = request->username_tag == NULL ? "" : request->username_tag; + mail_tag = mail_tag_find(dir->mail_hosts, tag); + user = mail_tag == NULL ? NULL : + user_directory_lookup(mail_tag->users, request->username_hash); + if (user != NULL) { - if (!director_request_existing(request, user, tag)) + i_assert(user->host->tag == mail_tag); + if (!director_request_existing(request, user)) return FALSE; - user_directory_refresh(users, user); + user_directory_refresh(mail_tag->users, user); dir_debug("request: %u refreshed timeout to %u", request->username_hash, user->timestamp); } else { @@ -307,7 +314,8 @@ request->username_hash); return FALSE; } - user = user_directory_add(users, request->username_hash, + user = user_directory_add(host->tag->users, + request->username_hash, host, ioloop_time); dir_debug("request: %u added timeout to %u (hosts_hash=%u)", request->username_hash, user->timestamp,
--- a/src/director/director.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/director.c Thu Oct 20 19:06:22 2016 +0300 @@ -629,7 +629,7 @@ struct director_host *orig_src, struct mail_host *host) { - struct user_directory *users = dir->users; + struct user_directory *users = host->tag->users; if (src != NULL) { if (orig_src == NULL) { @@ -652,7 +652,7 @@ struct director_host *orig_src, struct mail_host *host) { - struct user_directory *users = dir->users; + struct user_directory *users = host->tag->users; if (orig_src == NULL) { orig_src = dir->self_host; @@ -719,10 +719,12 @@ director_flush_user_continue(int result, struct director_kill_context *ctx) { struct director *dir = ctx->dir; - struct user *user = - user_directory_lookup(dir->users, ctx->username_hash); + ctx->callback_pending = FALSE; - ctx->callback_pending = FALSE; + struct user *user = user_directory_lookup(ctx->tag->users, + ctx->username_hash); + if (user != NULL) + director_user_kill_finish_delayed(dir, user,result == 1); if (result == 0) { struct istream *is = iostream_temp_finish(&ctx->reply, (size_t)-1); @@ -918,7 +920,6 @@ const char *data, void *context) { struct director_kill_context *ctx = context; - struct user_directory *users = ctx->dir->users; struct user *user; /* this is an asynchronous notification about user being killed. @@ -941,7 +942,7 @@ ctx->callback_pending = FALSE; - user = user_directory_lookup(users, ctx->username_hash); + user = user_directory_lookup(ctx->tag->users, ctx->username_hash); if (!DIRECTOR_KILL_CONTEXT_IS_VALID(user, ctx)) { /* user was already freed - ignore */ i_assert(ctx->to_move == NULL); @@ -995,6 +996,7 @@ user->kill_ctx = ctx = i_new(struct director_kill_context, 1); ctx->dir = dir; + ctx->tag = old_host->tag; ctx->username_hash = user->username_hash; ctx->kill_is_self_initiated = src->self; if (old_host != NULL) @@ -1024,7 +1026,7 @@ struct director_host *orig_src, unsigned int username_hash, struct mail_host *host) { - struct user_directory *users = dir->users; + struct user_directory *users = host->tag->users; struct user *user; /* 1. move this user's host, and set its "killing" flag to delay all of @@ -1164,12 +1166,13 @@ username_hash)); } -void director_user_killed(struct director *dir, unsigned int username_hash) +static void +director_user_tag_killed(struct director *dir, struct mail_tag *tag, + unsigned int username_hash) { - struct user_directory *users = dir->users; struct user *user; - user = user_directory_lookup(users, username_hash); + user = user_directory_lookup(tag->users, username_hash); if (user == NULL || !USER_IS_BEING_KILLED(user)) return; @@ -1200,14 +1203,24 @@ } } -void director_user_killed_everywhere(struct director *dir, - struct director_host *src, - struct director_host *orig_src, - unsigned int username_hash) +void director_user_killed(struct director *dir, unsigned int username_hash) +{ + struct mail_tag *const *tagp; + + array_foreach(mail_hosts_get_tags(dir->mail_hosts), tagp) + director_user_tag_killed(dir, *tagp, username_hash); +} + +static void +director_user_tag_killed_everywhere(struct director *dir, + struct mail_tag *tag, + struct director_host *src, + struct director_host *orig_src, + unsigned int username_hash) { struct user *user; - user = user_directory_lookup(dir->users, username_hash); + user = user_directory_lookup(tag->users, username_hash); if (user == NULL) { dir_debug("User %u no longer exists - ignoring USER-KILLED-EVERYWHERE", username_hash); @@ -1228,6 +1241,19 @@ director_send_user_killed_everywhere(dir, src, orig_src, username_hash); } +void director_user_killed_everywhere(struct director *dir, + struct director_host *src, + struct director_host *orig_src, + unsigned int username_hash) +{ + struct mail_tag *const *tagp; + + array_foreach(mail_hosts_get_tags(dir->mail_hosts), tagp) { + director_user_tag_killed_everywhere(dir, *tagp, src, orig_src, + username_hash); + } +} + static void director_state_callback_timeout(struct director *dir) { timeout_remove(&dir->to_callback); @@ -1296,9 +1322,9 @@ i_array_init(&dir->dir_hosts, 16); i_array_init(&dir->pending_requests, 16); i_array_init(&dir->connections, 8); - dir->users = user_directory_init(set->director_user_expire, - director_user_freed); - dir->mail_hosts = mail_hosts_init(set->director_consistent_hashing); + dir->mail_hosts = mail_hosts_init(set->director_user_expire, + set->director_consistent_hashing, + director_user_freed); dir->ipc_proxy = ipc_client_init(DIRECTOR_IPC_PROXY_PATH); dir->ring_min_version = DIRECTOR_VERSION_MINOR; @@ -1319,7 +1345,6 @@ director_connection_deinit(&conn, "Shutting down"); } - user_directory_deinit(&dir->users); mail_hosts_deinit(&dir->mail_hosts); mail_hosts_deinit(&dir->orig_config_hosts); @@ -1362,28 +1387,48 @@ } struct director_user_iter { + struct director *dir; + unsigned int tag_idx; struct user_directory_iter *user_iter; }; struct director_user_iter *director_iterate_users_init(struct director *dir) { struct director_user_iter *iter = i_new(struct director_user_iter, 1); - - iter->user_iter = user_directory_iter_init(dir->users); + iter->dir = dir; return iter; } struct user *director_iterate_users_next(struct director_user_iter *iter) { - return user_directory_iter_next(iter->user_iter); + const ARRAY_TYPE(mail_tag) *tags; + struct user *user; + + i_assert(iter != NULL); + + if (iter->user_iter == NULL) { + tags = mail_hosts_get_tags(iter->dir->mail_hosts); + if (iter->tag_idx >= array_count(tags)) + return NULL; + struct mail_tag *const *tagp = array_idx(tags, iter->tag_idx); + iter->user_iter = user_directory_iter_init((*tagp)->users); + } + user = user_directory_iter_next(iter->user_iter); + if (user == NULL) { + user_directory_iter_deinit(&iter->user_iter); + iter->tag_idx++; + return director_iterate_users_next(iter); + } else + return user; } void director_iterate_users_deinit(struct director_user_iter **_iter) { + i_assert(_iter != NULL && *_iter != NULL); struct director_user_iter *iter = *_iter; - *_iter = NULL; - user_directory_iter_deinit(&iter->user_iter); + if (iter->user_iter != NULL) + user_directory_iter_deinit(&iter->user_iter); i_free(iter); }
--- a/src/director/director.h Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/director.h Thu Oct 20 19:06:22 2016 +0300 @@ -34,6 +34,7 @@ struct director; struct mail_host; struct user; +struct director_user_init; enum user_kill_state { /* User isn't being killed */ @@ -72,6 +73,7 @@ struct director_kill_context { struct director *dir; + struct mail_tag *tag; unsigned int username_hash; struct ip_addr old_host_ip; bool kill_is_self_initiated; @@ -115,8 +117,6 @@ /* original mail hosts configured in config file. this is used only for doveadm lookups */ struct mail_host_list *orig_config_hosts; - /* temporary user -> host associations */ - struct user_directory *users; /* Number of users currently being moved */ unsigned int users_moving_count;
--- a/src/director/doveadm-connection.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/doveadm-connection.c Thu Oct 20 19:06:22 2016 +0300 @@ -82,7 +82,9 @@ string_t *str = t_str_new(1024); int ret; - orig_hosts_list = mail_hosts_init(conn->dir->set->director_consistent_hashing); + orig_hosts_list = mail_hosts_init(conn->dir->set->director_user_expire, + conn->dir->set->director_consistent_hashing, + NULL); (void)mail_hosts_parse_and_add(orig_hosts_list, conn->dir->set->director_mail_servers); @@ -450,6 +452,7 @@ if (cmd->iter == NULL) cmd->iter = director_iterate_users_init(dir); + while ((user = director_iterate_users_next(cmd->iter)) != NULL) { if (user->host != host) continue; @@ -551,11 +554,11 @@ doveadm_cmd_user_lookup(struct doveadm_connection *conn, const char *const *args) { - struct user_directory *users = conn->dir->users; struct user *user; struct mail_host *host; const char *username, *tag; unsigned int username_hash; + struct mail_tag *mail_tag; string_t *str = t_str_new(256); if (args[0] == NULL) { @@ -569,7 +572,9 @@ username_hash = director_get_username_hash(conn->dir, username); /* get user's current host */ - user = user_directory_lookup(users, username_hash); + mail_tag = mail_tag_find(conn->dir->mail_hosts, tag); + user = mail_tag == NULL ? NULL : + user_directory_lookup(mail_tag->users, username_hash); if (user == NULL) str_append(str, "\t0"); else { @@ -633,7 +638,6 @@ static int doveadm_cmd_user_move(struct doveadm_connection *conn, const char *const *args) { - struct user_directory *users = conn->dir->users; unsigned int username_hash; struct user *user; struct mail_host *host; @@ -652,7 +656,7 @@ if (str_to_uint(args[0], &username_hash) < 0) username_hash = director_get_username_hash(conn->dir, args[0]); - user = user_directory_lookup(users, username_hash); + user = user_directory_lookup(host->tag->users, username_hash); if (user != NULL && USER_IS_BEING_KILLED(user)) { o_stream_nsend_str(conn->output, "TRYAGAIN\n"); return 1;
--- a/src/director/mail-host.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/mail-host.c Thu Oct 20 19:06:22 2016 +0300 @@ -5,25 +5,17 @@ #include "bsearch-insert-pos.h" #include "crc32.h" #include "md5.h" +#include "user-directory.h" #include "mail-host.h" #define VHOST_MULTIPLIER 100 -struct mail_vhost { - unsigned int hash; - struct mail_host *host; -}; - -struct mail_tag { - /* "" = no tag */ - char *name; - ARRAY(struct mail_vhost) vhosts; -}; - struct mail_host_list { - ARRAY(struct mail_tag *) tags; + ARRAY_TYPE(mail_tag) tags; ARRAY_TYPE(mail_host) hosts; + user_free_hook_t *user_free_hook; unsigned int hosts_hash; + unsigned int user_expire_secs; bool consistent_hashing; bool vhosts_unsorted; bool have_vhosts; @@ -153,7 +145,7 @@ } } -static struct mail_tag * +struct mail_tag * mail_tag_find(struct mail_host_list *list, const char *tag_name) { struct mail_tag *const *tagp; @@ -175,6 +167,8 @@ tag = i_new(struct mail_tag, 1); tag->name = i_strdup(tag_name); i_array_init(&tag->vhosts, 16*VHOST_MULTIPLIER); + tag->users = user_directory_init(list->user_expire_secs, + list->user_free_hook); array_append(&list->tags, &tag, 1); } return tag; @@ -182,6 +176,7 @@ static void mail_tag_free(struct mail_tag *tag) { + user_directory_deinit(&tag->users); array_free(&tag->vhosts); i_free(tag->name); i_free(tag); @@ -513,12 +508,22 @@ return FALSE; } -struct mail_host_list *mail_hosts_init(bool consistent_hashing) +const ARRAY_TYPE(mail_tag) *mail_hosts_get_tags(struct mail_host_list *list) +{ + return &list->tags; +} + +struct mail_host_list * +mail_hosts_init(unsigned int user_expire_secs, bool consistent_hashing, + user_free_hook_t *user_free_hook) { struct mail_host_list *list; list = i_new(struct mail_host_list, 1); + list->user_expire_secs = user_expire_secs; list->consistent_hashing = consistent_hashing; + list->user_free_hook = user_free_hook; + i_array_init(&list->hosts, 16); i_array_init(&list->tags, 4); return list; @@ -556,7 +561,8 @@ struct mail_host_list *dest; struct mail_host *const *hostp, *dest_host; - dest = mail_hosts_init(src->consistent_hashing); + dest = mail_hosts_init(src->user_expire_secs, src->consistent_hashing, + src->user_free_hook); array_foreach(&src->hosts, hostp) { dest_host = mail_host_dup(*hostp); array_append(&dest->hosts, &dest_host, 1); @@ -564,3 +570,11 @@ mail_hosts_sort(dest); return dest; } + +void mail_hosts_sort_users(struct mail_host_list *list) +{ + struct mail_tag *const *tagp; + + array_foreach(&list->tags, tagp) + user_directory_sort((*tagp)->users); +}
--- a/src/director/mail-host.h Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/mail-host.h Thu Oct 20 19:06:22 2016 +0300 @@ -6,6 +6,22 @@ struct mail_host_list; +struct mail_vhost { + unsigned int hash; + struct mail_host *host; +}; + +/* mail_tags aren't removed/freed before mail_hosts_deinit(), so it's safe + to add pointers to them. */ +struct mail_tag { + /* "" = no tag */ + char *name; + ARRAY(struct mail_vhost) vhosts; + /* temporary user -> host associations */ + struct user_directory *users; +}; +ARRAY_DEFINE_TYPE(mail_tag, struct mail_tag *); + struct mail_host { struct mail_host_list *list; @@ -52,9 +68,19 @@ const ARRAY_TYPE(mail_host) *mail_hosts_get(struct mail_host_list *list); bool mail_hosts_have_tags(struct mail_host_list *list); -struct mail_host_list *mail_hosts_init(bool consistent_hashing); +const ARRAY_TYPE(mail_tag) *mail_hosts_get_tags(struct mail_host_list *list); +struct mail_tag * +mail_tag_find(struct mail_host_list *list, const char *tag_name); +struct user * +mail_hosts_find_user(struct mail_host_list *list, const char *tag_name, + unsigned int username_hash); + +struct mail_host_list * +mail_hosts_init(unsigned int user_expire_secs, bool consistent_hashing, + user_free_hook_t *user_free_hook); void mail_hosts_deinit(struct mail_host_list **list); struct mail_host_list *mail_hosts_dup(const struct mail_host_list *src); +void mail_hosts_sort_users(struct mail_host_list *list); #endif
--- a/src/director/main.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/main.c Thu Oct 20 19:06:22 2016 +0300 @@ -40,13 +40,23 @@ static struct timeout *to_proctitle_refresh; static ARRAY(enum director_socket_type) listener_socket_types; +static unsigned int director_total_users_count(void) +{ + struct mail_tag *const *tagp; + unsigned int count = 0; + + array_foreach(mail_hosts_get_tags(director->mail_hosts), tagp) + count += user_directory_count((*tagp)->users); + return count; +} + static void director_refresh_proctitle_timeout(void *context ATTR_UNUSED) { static uint64_t prev_requests = 0, prev_input = 0, prev_output; string_t *str; str = t_str_new(64); - str_printfa(str, "[%u users", user_directory_count(director->users)); + str_printfa(str, "[%u users", director_total_users_count()); if (director->users_moving_count > 0) str_printfa(str, ", %u moving", director->users_moving_count); str_printfa(str, ", %lu req/s",
--- a/src/director/notify-connection.c Tue Nov 01 14:36:19 2016 +0200 +++ b/src/director/notify-connection.c Thu Oct 20 19:06:22 2016 +0300 @@ -1,6 +1,7 @@ /* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "array.h" #include "ioloop.h" #include "istream.h" #include "master-service.h" @@ -17,13 +18,13 @@ struct director *dir; }; -static void notify_update_user(struct director *dir, const char *username, - unsigned int username_hash) +static void notify_update_user(struct director *dir, struct mail_tag *tag, + const char *username, unsigned int username_hash) { struct user *user; int diff; - user = user_directory_lookup(dir->users, username_hash); + user = user_directory_lookup(tag->users, username_hash); if (user == NULL) return; @@ -32,18 +33,20 @@ i_warning("notify: User %s refreshed too late (%d secs)", username, diff); } - user_directory_refresh(dir->users, user); + user_directory_refresh(tag->users, user); director_update_user(dir, dir->self_host, user); } static void notify_connection_input(struct notify_connection *conn) { + struct mail_tag *const *tagp; const char *line; unsigned int hash; while ((line = i_stream_read_next_line(conn->input)) != NULL) { - hash = director_get_username_hash(conn->dir->users, line); - notify_update_user(conn->dir, line, hash); + hash = director_get_username_hash(conn->dir, line); + array_foreach(mail_hosts_get_tags(conn->dir->mail_hosts), tagp) + notify_update_user(conn->dir, *tagp, line, hash); } if (conn->input->eof) { i_error("notify: read() unexpectedly returned EOF");