From: Timo Sirainen Date: Fri, 18 Aug 2017 08:51:36 +0000 (+0300) Subject: director: Run director/host changing doveadm commands only after ring is synced X-Git-Tag: 2.3.0.rc1~1130 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=02e78eb1e4fbe13d0bd815d3d3fc7200f88a1fc4;p=thirdparty%2Fdovecot%2Fcore.git 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. --- diff --git a/src/director/doveadm-connection.c b/src/director/doveadm-connection.c index f60128d4f5..3ab8a3eca0 100644 --- a/src/director/doveadm-connection.c +++ b/src/director/doveadm-connection.c @@ -34,6 +34,10 @@ enum doveadm_director_cmd_ret { 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 doveadm_connection { 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; + bool handshaked:1; }; @@ -71,6 +78,7 @@ static void doveadm_connection_set_io(struct doveadm_connection *conn); 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, @@ -753,24 +761,25 @@ struct { 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 @@ -781,6 +790,8 @@ doveadm_connection_ring_sync_timeout(struct doveadm_connection *conn) doveadm_connection_set_io(conn); io_set_pending(conn->io); + + i_free_and_null(conn->cmd_pending_args); } static void @@ -810,6 +821,17 @@ doveadm_connection_cmd_run(struct doveadm_connection *conn, { 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; @@ -825,6 +847,15 @@ doveadm_connection_cmd_run(struct doveadm_connection *conn, 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) {