Skip to content

Commit

Permalink
director: Keep per-tag directory
Browse files Browse the repository at this point in the history
  • Loading branch information
cmouse authored and GitLab committed Nov 8, 2016
1 parent 1a7ed93 commit b44033e
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 73 deletions.
6 changes: 3 additions & 3 deletions src/director/director-connection.c
Expand Up @@ -502,7 +502,7 @@ director_user_refresh(struct director_connection *conn,
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;

Expand Down Expand Up @@ -1236,7 +1236,7 @@ static bool director_handshake_cmd_done(struct director_connection *conn)
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);
Expand Down Expand Up @@ -1908,7 +1908,7 @@ static int director_connection_send_users(struct director_connection *conn)
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);
Expand Down
32 changes: 20 additions & 12 deletions src/director/director-request.c
Expand Up @@ -96,8 +96,12 @@ static void director_request_timeout(struct director *dir)
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 &&
Expand Down Expand Up @@ -177,11 +181,9 @@ static void ring_log_delayed_warning(struct director *dir)
}

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)) {
Expand All @@ -208,12 +210,13 @@ director_request_existing(struct director_request *request, struct user *user,
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;
Expand Down Expand Up @@ -272,10 +275,10 @@ director_request_existing(struct director_request *request, struct user *user,
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 */
Expand All @@ -286,12 +289,16 @@ bool director_request_continue(struct director_request *request)
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 {
Expand All @@ -312,7 +319,8 @@ bool director_request_continue(struct director_request *request)
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,
Expand Down
95 changes: 70 additions & 25 deletions src/director/director.c
Expand Up @@ -626,7 +626,7 @@ void director_remove_host(struct director *dir, struct director_host *src,
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) {
Expand All @@ -649,7 +649,7 @@ void director_flush_host(struct director *dir, struct director_host *src,
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;
Expand Down Expand Up @@ -716,11 +716,13 @@ static void
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;

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);
char *data;
Expand Down Expand Up @@ -921,7 +923,6 @@ static void director_kill_user_callback(enum ipc_client_cmd_state state,
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.
Expand All @@ -944,7 +945,7 @@ static void director_kill_user_callback(enum ipc_client_cmd_state state,

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);
Expand Down Expand Up @@ -998,6 +999,7 @@ director_kill_user(struct director *dir, struct director_host *src,

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)
Expand Down Expand Up @@ -1027,7 +1029,7 @@ void director_move_user(struct director *dir, struct director_host *src,
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
Expand Down Expand Up @@ -1167,12 +1169,13 @@ director_send_user_killed_everywhere(struct director *dir,
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;

Expand Down Expand Up @@ -1203,14 +1206,24 @@ void director_user_killed(struct director *dir, unsigned int username_hash)
}
}

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);
Expand All @@ -1231,6 +1244,19 @@ void director_user_killed_everywhere(struct director *dir,
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);
Expand Down Expand Up @@ -1299,9 +1325,9 @@ director_init(const struct director_settings *set,
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;
Expand All @@ -1322,7 +1348,6 @@ void director_deinit(struct director **_dir)
director_connection_deinit(&conn, "Shutting down");
}

user_directory_deinit(&dir->users);
mail_hosts_deinit(&dir->mail_hosts);
mail_hosts_deinit(&dir->orig_config_hosts);

Expand Down Expand Up @@ -1365,28 +1390,48 @@ void dir_debug(const char *fmt, ...)
}

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);
}

Expand Down
4 changes: 2 additions & 2 deletions src/director/director.h
Expand Up @@ -34,6 +34,7 @@
struct director;
struct mail_host;
struct user;
struct director_user_init;

enum user_kill_state {
/* User isn't being killed */
Expand Down Expand Up @@ -72,6 +73,7 @@ typedef void director_state_change_callback_t(struct director *dir);

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;
Expand Down Expand Up @@ -115,8 +117,6 @@ struct director {
/* 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;

Expand Down

0 comments on commit b44033e

Please sign in to comment.