ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#define RING_NOCONN_WARNING_DELAY_MSECS (2*1000)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "ring not handshaked",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "ring not synced",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "kill waiting"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh enum director_request_delay_reason delay_reason;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void director_request_free(struct director_request *request)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic const char *
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikdirector_request_get_timeout_error(struct director_request *request,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Timeout because %s - queued for %u secs (",
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh (unsigned int)(ioloop_time - request->create_time));
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_append(str, "Ring has never been synced");
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik secs = ioloop_time - request->dir->ring_last_sync_time;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Ring synced for %u secs", secs);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Ring not synced for %u secs", secs);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", user refreshed %u secs ago",
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik (unsigned int)(ioloop_time - user->timestamp));
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", hash=%u", request->username_hash);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", tag=%s", request->username_tag);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void director_request_timeout(struct director *dir)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik while (array_count(&dir->pending_requests) > 0) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik requestp = array_idx_modifiable(&dir->pending_requests, 0);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik DIRECTOR_REQUEST_TIMEOUT_SECS > ioloop_time)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik const char *tag_name = request->username_tag == NULL ? "" :
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik struct mail_tag *tag = mail_tag_find(dir->mail_hosts, tag_name);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user_directory_lookup(tag->users, request->username_hash);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik errormsg = director_request_get_timeout_error(request,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->delay_reason == REQUEST_DELAY_WEAK) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* weakness appears to have gotten stuck. this is a
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik bug, but try to fix it for future requests by
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik removing the weakness. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->callback(NULL, NULL, errormsg, request->context);
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh if (array_count(&dir->pending_requests) == 0 && dir->to_request != NULL)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikvoid director_request(struct director *dir, const char *username,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik director_request_callback *callback, void *context)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (!director_get_username_hash(dir, username,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik callback(NULL, NULL, "Failed to expand director_username_hash", context);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->username_tag = tag[0] == '\0' ? NULL : i_strdup(tag);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* need to queue it */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik timeout_add(DIRECTOR_REQUEST_TIMEOUT_SECS * 1000,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik array_append(&dir->pending_requests, &request, 1);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic void ring_noconn_warning(struct director *dir)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "until all directors have connected");
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh i_warning("Delaying new user requests until ring is synced");
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void ring_log_delayed_warning(struct director *dir)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir->to_handshake_warning = timeout_add(RING_NOCONN_WARNING_DELAY_MSECS,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhdirector_request_existing(struct director_request *request, struct user *user)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* delay processing this user's connections until
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh its existing connections have been killed */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for kill to finish",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (dir->right == NULL && dir->ring_synced) {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* looks like all the other directors have died. we can do
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh whatever we want without breaking anything. remove the
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user's weakness just in case it was set to TRUE when we
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik had more directors. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* wait for user to become non-weak */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for weakness",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (!user_directory_user_is_near_expiring(user->host->tag->users, user))
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* user is close to being expired. another director may have
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh already expired it. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* try again later once ring is synced */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->delay_reason = REQUEST_DELAY_RINGNOTSYNCED;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for sync for making weak",
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek /* doesn't matter, other directors would
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek assign the user the same way regardless */
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek dir_debug("request: %u would be weak, but host doesn't change", request->username_hash);
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek /* We have to worry about two separate timepoints in here:
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh a) some directors think the user isn't expiring, and
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh others think the user is near expiring
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek b) some directors think the user is near expiring, and
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh others think the user has already expired
return TRUE;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
T_BEGIN {
} T_END;
return TRUE;
return FALSE;
return TRUE;