Mercurial > dovecot > core-2.2
changeset 20546:e8b44e9197e2
dict-client: When we get disconnected, reconnect and re-send commands.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Mon, 25 Jul 2016 17:32:11 -0400 |
parents | 0be59f9f40ab |
children | 879b2a660a95 |
files | src/lib-dict/dict-client.c |
diffstat | 1 files changed, 60 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-dict/dict-client.c Mon Jul 25 17:08:18 2016 -0400 +++ b/src/lib-dict/dict-client.c Mon Jul 25 17:32:11 2016 -0400 @@ -91,6 +91,7 @@ unsigned int result_idx; bool async; + bool seen_results; bool finished; bool deinit; }; @@ -111,6 +112,8 @@ static struct connection_list *dict_connections; static int client_dict_connect(struct client_dict *dict, const char **error_r); +static int client_dict_reconnect(struct client_dict *dict, const char *reason, + const char **error_r); static void client_dict_disconnect(struct client_dict *dict, const char *reason); static struct client_dict_cmd * @@ -187,17 +190,18 @@ { struct client_dict_cmd *const *cmds; unsigned int count; + const char *error; cmds = array_get(&dict->cmds, &count); i_assert(count > 0); int input_diff = timeval_diff_msecs(&ioloop_timeval, &dict->last_input); int cmd_diff = timeval_diff_msecs(&ioloop_timeval, &cmds[0]->start_time); - client_dict_disconnect(dict, t_strdup_printf( + (void)client_dict_reconnect(dict, t_strdup_printf( "Timeout: No input from dict for %u.%03u secs " "(%u commands pending, oldest sent %u.%03u secs ago: %s)", input_diff/1000, input_diff%1000, count, - cmd_diff/1000, cmd_diff%1000, cmds[0]->query)); + cmd_diff/1000, cmd_diff%1000, cmds[0]->query), &error); } static int @@ -245,8 +249,7 @@ } if (ret < 0 && retry) { /* Reconnect and try again. */ - client_dict_disconnect(dict, error); - if (client_dict_connect(dict, &error) < 0) + if (client_dict_reconnect(dict, error, &error) < 0) ; else if (client_dict_cmd_query_send(dict, cmd->query) < 0) { error = t_strdup_printf("write(%s) failed: %s", dict->conn.conn.name, @@ -479,6 +482,58 @@ connection_disconnect(&dict->conn.conn); } +static int client_dict_reconnect(struct client_dict *dict, const char *reason, + const char **error_r) +{ + ARRAY(struct client_dict_cmd *) retry_cmds; + struct client_dict_cmd *const *cmdp, *cmd; + const char *error; + int ret; + + t_array_init(&retry_cmds, array_count(&dict->cmds)); + for (unsigned int i = 0; i < array_count(&dict->cmds); ) { + cmdp = array_idx(&dict->cmds, i); + if (!(*cmdp)->retry_errors) { + i++; + } else if ((*cmdp)->iter != NULL && + (*cmdp)->iter->seen_results) { + /* don't retry iteration that already returned + something to the caller. otherwise we'd return + duplicates. */ + i++; + } else { + array_append(&retry_cmds, cmdp, 1); + array_delete(&dict->cmds, i, 1); + } + } + client_dict_disconnect(dict, reason); + if (client_dict_connect(dict, error_r) < 0) { + reason = t_strdup_printf("%s - reconnect failed: %s", + reason, *error_r); + array_foreach(&retry_cmds, cmdp) { + dict_cmd_callback_error(*cmdp, reason, TRUE); + client_dict_cmd_unref(*cmdp); + } + return -1; + } + if (array_count(&retry_cmds) == 0) + return 0; + i_warning("%s - reconnected", reason); + + ret = 0; error = ""; + array_foreach(&retry_cmds, cmdp) { + cmd = *cmdp; + /* if it fails again, don't retry anymore */ + cmd->retry_errors = FALSE; + if (ret < 0) { + dict_cmd_callback_error(cmd, error, TRUE); + client_dict_cmd_unref(cmd); + } else if (!client_dict_cmd_send(dict, &cmd, &error)) + ret = -1; + } + return ret; +} + static void dict_conn_destroy(struct connection *_conn) { struct dict_connection *conn = (struct dict_connection *)_conn; @@ -847,6 +902,7 @@ *value_r = results[ctx->result_idx].value; ctx->ctx.has_more = TRUE; ctx->result_idx++; + ctx->seen_results = TRUE; return TRUE; } ctx->ctx.has_more = !ctx->finished;