Mercurial > dovecot > core-2.2
changeset 22537:4e3e963c32f0
director: Run director/host changing doveadm commands only after ring is synced
If the ring sync is still pending, the doveadm command may become reverted.
This doesn't fully prevent problems caused by sending doveadm commands
simultaneously to multiple directors, but it should prevent issues when
only a single director is used for doveadm commands.
It would have been nice to enable this also for HOST/DIRECTOR-LIST commands,
but they don't support returning a ring timeout error without changing the
protocol. It's a bit too much effort to change that for now.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Fri, 18 Aug 2017 11:51:36 +0300 |
parents | 5f09f6aa089b |
children | 0819f28fc76b |
files | src/director/doveadm-connection.c |
diffstat | 1 files changed, 48 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/src/director/doveadm-connection.c Mon Aug 14 10:29:47 2017 +0300 +++ b/src/director/doveadm-connection.c Fri Aug 18 11:51:36 2017 +0300 @@ -34,6 +34,10 @@ DOVEADM_DIRECTOR_CMD_RET_RING_SYNC_OK, }; +enum doveadm_director_cmd_flag { + DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC = 0x01, +}; + typedef void doveadm_connection_ring_sync_callback_t(struct doveadm_connection *); @@ -60,6 +64,9 @@ struct director_reset_cmd *reset_cmd; doveadm_connection_ring_sync_callback_t *ring_sync_callback; + const char **cmd_pending_args; + unsigned int cmd_pending_idx; + unsigned int handshaked:1; }; @@ -71,6 +78,7 @@ static void doveadm_connection_deinit(struct doveadm_connection **_conn); static void doveadm_connection_ring_sync_list_move(struct doveadm_connection *conn); +static void doveadm_connection_cmd_run_synced(struct doveadm_connection *conn); static enum doveadm_director_cmd_ret doveadm_cmd_host_list(struct doveadm_connection *conn, @@ -760,24 +768,25 @@ const char *name; enum doveadm_director_cmd_ret (*cmd) (struct doveadm_connection *conn, const char *const *args); + enum doveadm_director_cmd_flag flags; } doveadm_director_commands[] = { - { "HOST-LIST", doveadm_cmd_host_list }, - { "HOST-LIST-REMOVED", doveadm_cmd_host_list_removed }, - { "DIRECTOR-LIST", doveadm_cmd_director_list }, - { "DIRECTOR-ADD", doveadm_cmd_director_add }, - { "DIRECTOR-REMOVE", doveadm_cmd_director_remove }, - { "HOST-SET", doveadm_cmd_host_set }, - { "HOST-UPDATE", doveadm_cmd_host_update }, - { "HOST-UP", doveadm_cmd_host_up }, - { "HOST-DOWN", doveadm_cmd_host_down }, - { "HOST-REMOVE", doveadm_cmd_host_remove }, - { "HOST-FLUSH", doveadm_cmd_host_flush }, - { "HOST-RESET-USERS", doveadm_cmd_host_reset_users }, - { "USER-LOOKUP", doveadm_cmd_user_lookup }, - { "USER-LIST", doveadm_cmd_user_list }, - { "USER-MOVE", doveadm_cmd_user_move }, - { "USER-KICK", doveadm_cmd_user_kick }, - { "USER-KICK-ALT", doveadm_cmd_user_kick_alt }, + { "HOST-LIST", doveadm_cmd_host_list, 0 }, + { "HOST-LIST-REMOVED", doveadm_cmd_host_list_removed, 0 }, + { "DIRECTOR-LIST", doveadm_cmd_director_list, 0 }, + { "DIRECTOR-ADD", doveadm_cmd_director_add, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "DIRECTOR-REMOVE", doveadm_cmd_director_remove, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-SET", doveadm_cmd_host_set, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-UPDATE", doveadm_cmd_host_update, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-UP", doveadm_cmd_host_up, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-DOWN", doveadm_cmd_host_down, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-REMOVE", doveadm_cmd_host_remove, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-FLUSH", doveadm_cmd_host_flush, DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC }, + { "HOST-RESET-USERS", doveadm_cmd_host_reset_users, 0 }, + { "USER-LOOKUP", doveadm_cmd_user_lookup, 0 }, + { "USER-LIST", doveadm_cmd_user_list, 0 }, + { "USER-MOVE", doveadm_cmd_user_move, 0 }, + { "USER-KICK", doveadm_cmd_user_kick, 0 }, + { "USER-KICK-ALT", doveadm_cmd_user_kick_alt, 0 }, }; static void @@ -788,6 +797,8 @@ doveadm_connection_set_io(conn); io_set_pending(conn->io); + + i_free_and_null(conn->cmd_pending_args); } static void @@ -817,6 +828,17 @@ { enum doveadm_director_cmd_ret ret; + if ((doveadm_director_commands[i].flags & + DOVEADM_DIRECTOR_CMD_FLAG_PRE_RING_SYNC) != 0 && + !conn->dir->ring_synced) { + /* wait for ring to be synced before running the command */ + conn->cmd_pending_args = p_strarray_dup(default_pool, args); + conn->cmd_pending_idx = i; + doveadm_connection_set_ring_sync_callback(conn, + doveadm_connection_cmd_run_synced); + return DOVEADM_DIRECTOR_CMD_RET_UNFINISHED; + } + ret = doveadm_director_commands[i].cmd(conn, args); if (ret != DOVEADM_DIRECTOR_CMD_RET_RING_SYNC_OK) return ret; @@ -832,6 +854,15 @@ return DOVEADM_DIRECTOR_CMD_RET_RING_SYNC_OK; } +static void doveadm_connection_cmd_run_synced(struct doveadm_connection *conn) +{ + const char **args = conn->cmd_pending_args; + + conn->cmd_pending_args = NULL; + (void)doveadm_connection_cmd_run(conn, args, conn->cmd_pending_idx); + i_free(args); +} + static enum doveadm_director_cmd_ret doveadm_connection_cmd(struct doveadm_connection *conn, const char *line) {