bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "lib.h"
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#include "array.h"
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen#include "llist.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "str.h"
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen#include "strescape.h"
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen#include "file-lock.h"
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#include "time-util.h"
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#include "connection.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "ostream.h"
87e603100685f9eb7faf995d2600edd0a578dd0cTimo Sirainen#include "eacces-error.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "dict-private.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "dict-client.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include <unistd.h>
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include <fcntl.h>
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen/* Disconnect from dict server after this many milliseconds of idling after
8f079b04c103e073e57fa8b85cf69b14b0260ea4Timo Sirainen sending a command. Because dict server does blocking dict accesses, it can
8f079b04c103e073e57fa8b85cf69b14b0260ea4Timo Sirainen handle only one client at a time. This is why the default timeout is zero,
8f079b04c103e073e57fa8b85cf69b14b0260ea4Timo Sirainen so that there won't be many dict processes just doing nothing. Zero means
8f079b04c103e073e57fa8b85cf69b14b0260ea4Timo Sirainen that the socket is disconnected immediately after returning to ioloop. */
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen#define DICT_CLIENT_DEFAULT_TIMEOUT_MSECS 0
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen/* Abort dict lookup after this many seconds. */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#define DICT_CLIENT_REQUEST_TIMEOUT_MSECS 30000
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen/* When dict lookup timeout is reached, wait a bit longer if the last dict
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen ioloop wait was shorter than this. */
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen#define DICT_CLIENT_REQUEST_TIMEOUT_MIN_LAST_IOLOOP_WAIT_MSECS 1000
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen/* Log a warning if dict lookup takes longer than this many milliseconds. */
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen#define DICT_CLIENT_DEFAULT_WARN_SLOW_MSECS 5000
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstruct client_dict_cmd {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen int refcount;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct timeval start_time;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen char *query;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int async_id;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct timeval async_id_received_time;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen uint64_t start_global_ioloop_usecs;
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen uint64_t start_dict_ioloop_usecs;
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen uint64_t start_lock_usecs;
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen bool reconnected;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool retry_errors;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool no_replies;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool unfinished;
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen bool background;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen void (*callback)(struct client_dict_cmd *cmd,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen enum dict_protocol_reply reply, const char *value,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *const *extra_args, const char *error,
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen bool disconnected);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_iterate_context *iter;
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen struct client_dict_transaction_context *trans;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_lookup_callback_t *lookup;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_transaction_commit_callback_t *commit;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen void *context;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } api_callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen};
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstruct dict_connection {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct connection conn;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen};
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_connection conn;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen char *uri, *username;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_data_type value_type;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen unsigned warn_slow_msecs;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen time_t last_failed_connect;
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen char *last_connect_error;
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct ioloop *ioloop, *prev_ioloop;
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen struct io_wait_timer *wait_timer;
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen uint64_t last_timer_switch_usecs;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct timeout *to_requests;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen struct timeout *to_idle;
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen unsigned int idle_msecs;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ARRAY(struct client_dict_cmd *) cmds;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *transactions;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int transaction_id_counter;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstruct client_dict_iter_result {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *key, *value;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict_iterate_context {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict_iterate_context ctx;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen char *error;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen const char **paths;
980b0dbdcbeed1a15fdbf4ec1d00352d71a66c5dTimo Sirainen enum dict_iterate_flags flags;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen pool_t results_pool;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ARRAY(struct client_dict_iter_result) results;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen unsigned int result_idx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen bool cmd_sent;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen bool seen_results;
9e7a30991415f714b609f650105596371a58216dTimo Sirainen bool finished;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool deinit;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict_transaction_context {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict_transaction_context ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *prev, *next;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen char *first_query;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen char *error;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int id;
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen unsigned int query_count;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool sent_begin:1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic struct connection_list *dict_connections;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int client_dict_connect(struct client_dict *dict, const char **error_r);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainenstatic int client_dict_reconnect(struct client_dict *dict, const char *reason,
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen const char **error_r);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict, const char *reason);
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainenstatic const char *dict_wait_warnings(const struct client_dict_cmd *cmd);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic struct client_dict_cmd *
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_init(struct client_dict *dict, const char *query)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
38fa43690a1cdc1917245f5f834ec40a89e83d91Timo Sirainen io_loop_time_refresh();
38fa43690a1cdc1917245f5f834ec40a89e83d91Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = i_new(struct client_dict_cmd, 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->refcount = 1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->dict = dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->query = i_strdup(query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->start_time = ioloop_timeval;
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen cmd->start_global_ioloop_usecs = ioloop_global_wait_usecs;
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen cmd->start_dict_ioloop_usecs = io_wait_timer_get_usecs(dict->wait_timer);
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen cmd->start_lock_usecs = file_lock_wait_get_total_usecs();
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return cmd;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_cmd_ref(struct client_dict_cmd *cmd)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(cmd->refcount > 0);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->refcount++;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen}
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic bool client_dict_cmd_unref(struct client_dict_cmd *cmd)
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(cmd->refcount > 0);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (--cmd->refcount > 0)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return TRUE;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen i_assert(cmd->trans == NULL);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(cmd->query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(cmd);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return FALSE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void dict_pre_api_callback(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->prev_ioloop != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* Don't let callback see that we've created our
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen internal ioloop in case it wants to add some ios
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen or timeouts. */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen current_ioloop = dict->prev_ioloop;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen }
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen}
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void dict_post_api_callback(struct client_dict *dict)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->prev_ioloop != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen current_ioloop = dict->ioloop;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* stop client_dict_wait() */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_stop(dict->ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen}
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic bool
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainendict_cmd_callback_line(struct client_dict_cmd *cmd, const char *const *args)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *value = args[0];
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen enum dict_protocol_reply reply;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen if (value == NULL) {
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen /* "" is a valid iteration reply */
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen reply = DICT_PROTOCOL_REPLY_ITER_FINISHED;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen } else {
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen reply = value[0];
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen value++;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen args++;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->unfinished = FALSE;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen cmd->callback(cmd, reply, value, args, NULL, FALSE);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return !cmd->unfinished;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic void
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainendict_cmd_callback_error(struct client_dict_cmd *cmd, const char *error,
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen bool disconnected)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *null_arg = NULL;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->unfinished = FALSE;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen if (cmd->callback != NULL) {
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen cmd->callback(cmd, DICT_PROTOCOL_REPLY_ERROR,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen "", &null_arg, error, disconnected);
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(!cmd->unfinished);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainenstatic struct client_dict_cmd *
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainenclient_dict_cmd_first_nonbg(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
d0fa29db7def334c142f46507a7d0c0bd6c70932Timo Sirainen struct client_dict_cmd *const *cmds;
8d72f209049edf50f5cd40c56efd2c0b33f892a2Timo Sirainen unsigned int i, count;
79b0f6ec3e5fde8f878bd85f4a1c3d669af66ebeTimo Sirainen
d0fa29db7def334c142f46507a7d0c0bd6c70932Timo Sirainen cmds = array_get(&dict->cmds, &count);
8d72f209049edf50f5cd40c56efd2c0b33f892a2Timo Sirainen for (i = 0; i < count; i++) {
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen if (!cmds[i]->background)
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen return cmds[i];
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen }
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen return NULL;
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen}
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainenstatic void client_dict_input_timeout(struct client_dict *dict)
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen{
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen struct client_dict_cmd *cmd;
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen const char *error;
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen uint64_t msecs_in_last_dict_ioloop_wait;
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen int cmd_diff;
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen /* find the first non-background command. there must be at least one. */
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen cmd = client_dict_cmd_first_nonbg(dict);
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen i_assert(cmd != NULL);
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen cmd_diff = timeval_diff_msecs(&ioloop_timeval, &cmd->start_time);
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen if (cmd_diff < DICT_CLIENT_REQUEST_TIMEOUT_MSECS) {
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen /* need to re-create this timeout. the currently-oldest
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen command was added when another command was still
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen running with an older timeout. */
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen timeout_remove(&dict->to_requests);
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen dict->to_requests =
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen timeout_add(DICT_CLIENT_REQUEST_TIMEOUT_MSECS - cmd_diff,
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen client_dict_input_timeout, dict);
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen return;
8d72f209049edf50f5cd40c56efd2c0b33f892a2Timo Sirainen }
d0fa29db7def334c142f46507a7d0c0bd6c70932Timo Sirainen
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen /* If we've gotten here because all the time was spent in other ioloops
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen or locks, make sure there's a bit of time waiting for the dict
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen ioloop as well. There's a good chance that the reply can be read. */
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen msecs_in_last_dict_ioloop_wait =
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen (io_wait_timer_get_usecs(dict->wait_timer) -
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen dict->last_timer_switch_usecs + 999) / 1000;
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen if (msecs_in_last_dict_ioloop_wait < DICT_CLIENT_REQUEST_TIMEOUT_MIN_LAST_IOLOOP_WAIT_MSECS) {
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen timeout_remove(&dict->to_requests);
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen dict->to_requests =
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen timeout_add(DICT_CLIENT_REQUEST_TIMEOUT_MIN_LAST_IOLOOP_WAIT_MSECS -
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen msecs_in_last_dict_ioloop_wait,
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen client_dict_input_timeout, dict);
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen return;
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen }
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen (void)client_dict_reconnect(dict, t_strdup_printf(
cf1b9b686bca3e0de3dda1a95dab66ad4590d8efTimo Sirainen "Dict server timeout: %s "
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen "(%u commands pending, oldest sent %u.%03u secs ago: %s, %s)",
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen connection_input_timeout_reason(&dict->conn.conn),
c1814529bdc9f1468b4fe75beb080991ee3feea0Timo Sirainen array_count(&dict->cmds),
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen cmd_diff/1000, cmd_diff%1000, cmd->query,
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen dict_wait_warnings(cmd)), &error);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic int
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_query_send(struct client_dict *dict, const char *query)
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct const_iovec iov[2];
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen ssize_t ret;
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen iov[0].iov_base = query;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen iov[0].iov_len = strlen(query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen iov[1].iov_base = "\n";
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen iov[1].iov_len = 1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = o_stream_sendv(dict->conn.conn.output, iov, 2);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ret < 0)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert((size_t)ret == iov[0].iov_len + 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return 0;
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen}
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic bool
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_send(struct client_dict *dict, struct client_dict_cmd **_cmd,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char **error_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd = *_cmd;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *error = NULL;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool retry = cmd->retry_errors;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen int ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen *_cmd = NULL;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* we're no longer idling. even with no_replies=TRUE we're going to
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen wait for COMMIT/ROLLBACK. */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dict->to_idle);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (client_dict_connect(dict, &error) < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen retry = FALSE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = client_dict_cmd_query_send(dict, cmd->query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ret < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error = t_strdup_printf("write(%s) failed: %s", dict->conn.conn.name,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen o_stream_get_error(dict->conn.conn.output));
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ret < 0 && retry) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* Reconnect and try again. */
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen if (client_dict_reconnect(dict, error, &error) < 0)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen else if (client_dict_cmd_query_send(dict, cmd->query) < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error = t_strdup_printf("write(%s) failed: %s", dict->conn.conn.name,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen o_stream_get_error(dict->conn.conn.output));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = 0;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (cmd->no_replies) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* just send and forget */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_cmd_unref(cmd);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else if (ret < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(error != NULL);
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen /* we didn't successfully send this command to dict */
904cdf7f28e5ba801bbd4a9baf3c50d847ac14e1Timo Sirainen dict_cmd_callback_error(cmd, error, cmd->reconnected);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_cmd_unref(cmd);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (error_r != NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen *error_r = error;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return FALSE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else {
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen if (dict->to_requests == NULL && !cmd->background) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->to_requests =
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen timeout_add(DICT_CLIENT_REQUEST_TIMEOUT_MSECS,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_input_timeout, dict);
9e7a30991415f714b609f650105596371a58216dTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_append(&dict->cmds, &cmd, 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return TRUE;
9e7a30991415f714b609f650105596371a58216dTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainenstatic bool
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_transaction_send_begin(struct client_dict_transaction_context *ctx)
feac4d832101e7090a134ed4edb16610877c07c7Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *query, *error;
feac4d832101e7090a134ed4edb16610877c07c7Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(ctx->error == NULL);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->sent_begin = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* transactions commands don't have replies. only COMMIT has. */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u", DICT_PROTOCOL_CMD_BEGIN, ctx->id);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->no_replies = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->retry_errors = TRUE;
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen if (!client_dict_cmd_send(dict, &cmd, &error)) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->error = i_strdup(error);
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen return FALSE;
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen }
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen return TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_send_transaction_query(struct client_dict_transaction_context *ctx,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *query)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *error;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->error != NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen if (!ctx->sent_begin) {
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen if (!client_dict_transaction_send_begin(ctx))
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen return;
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen ctx->query_count++;
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen if (ctx->first_query == NULL)
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen ctx->first_query = i_strdup(query);
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->no_replies = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (!client_dict_cmd_send(dict, &cmd, &error))
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->error = i_strdup(error);
feac4d832101e7090a134ed4edb16610877c07c7Timo Sirainen}
feac4d832101e7090a134ed4edb16610877c07c7Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic bool client_dict_is_finished(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return dict->transactions == NULL && array_count(&dict->cmds) == 0;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_timeout(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen if (client_dict_is_finished(dict))
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen client_dict_disconnect(dict, "Idle disconnection");
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainenstatic bool client_dict_have_nonbackground_cmds(struct client_dict *dict)
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen{
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen struct client_dict_cmd *const *cmdp;
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen array_foreach(&dict->cmds, cmdp) {
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen if (!(*cmdp)->background)
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen return TRUE;
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen }
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen return FALSE;
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen}
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_add_timeout(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen if (dict->to_idle != NULL) {
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen if (dict->idle_msecs > 0)
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen timeout_reset(dict->to_idle);
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen } else if (client_dict_is_finished(dict)) {
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen dict->to_idle = timeout_add(dict->idle_msecs,
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_timeout, dict);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dict->to_requests);
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen } else if (dict->transactions == NULL &&
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen !client_dict_have_nonbackground_cmds(dict)) {
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen /* we had non-background commands, but now we're back to
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen having only background commands. remove timeouts. */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dict->to_requests);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen }
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainenstatic void client_dict_cmd_backgrounded(struct client_dict *dict)
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen{
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen if (dict->to_requests == NULL)
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen return;
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen if (!client_dict_have_nonbackground_cmds(dict)) {
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen /* we only have background-commands.
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen remove the request timeout. */
9fa33a0c56e1d9a09c72698097ee269fa04e07b1Timo Sirainen timeout_remove(&dict->to_requests);
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen }
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen}
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic int
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainendict_conn_assign_next_async_id(struct dict_connection *conn, const char *line)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct client_dict_cmd *const *cmds;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int i, count, async_id;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(line[0] == DICT_PROTOCOL_REPLY_ASYNC_ID);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (str_to_uint(line+1, &async_id) < 0 || async_id == 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_error("%s: Received invalid async-id line: %s",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen conn->conn.name, line);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return -1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmds = array_get(&conn->dict->cmds, &count);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen for (i = 0; i < count; i++) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmds[i]->async_id == 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmds[i]->async_id = async_id;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmds[i]->async_id_received_time = ioloop_timeval;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return 0;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_error("%s: Received async-id line, but all %u commands already have it: %s",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen conn->conn.name, count, line);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return -1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen}
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic int dict_conn_find_async_id(struct dict_connection *conn,
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen const char *async_arg,
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen const char *line, unsigned int *idx_r)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct client_dict_cmd *const *cmds;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int i, count, async_id;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(async_arg[0] == DICT_PROTOCOL_REPLY_ASYNC_REPLY);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (str_to_uint(async_arg+1, &async_id) < 0 || async_id == 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_error("%s: Received invalid async-reply line: %s",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen conn->conn.name, line);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return -1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmds = array_get(&conn->dict->cmds, &count);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen for (i = 0; i < count; i++) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmds[i]->async_id == async_id) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen *idx_r = i;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return 0;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_error("%s: Received reply for nonexistent async-id %u: %s",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen conn->conn.name, async_id, line);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return -1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen}
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic int dict_conn_input_line(struct connection *_conn, const char *line)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_connection *conn = (struct dict_connection *)_conn;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = conn->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *const *cmds;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen const char *const *args;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int i, count;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen bool finished;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->to_requests != NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen timeout_reset(dict->to_requests);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (line[0] == DICT_PROTOCOL_REPLY_ASYNC_ID)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return dict_conn_assign_next_async_id(conn, line) < 0 ? -1 : 1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmds = array_get(&conn->dict->cmds, &count);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (count == 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_error("%s: Received reply without pending commands: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->conn.conn.name, line);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen args = t_strsplit_tabescaped(line);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (args[0] != NULL && args[0][0] == DICT_PROTOCOL_REPLY_ASYNC_REPLY) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (dict_conn_find_async_id(conn, args[0], line, &i) < 0)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return -1;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen args++;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen } else {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i = 0;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(!cmds[i]->no_replies);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen client_dict_cmd_ref(cmds[i]);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen finished = dict_cmd_callback_line(cmds[i], args);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (!client_dict_cmd_unref(cmds[i])) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* disconnected during command handling */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (!finished) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* more lines needed for this command */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return 1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen client_dict_cmd_unref(cmds[i]);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen array_delete(&dict->cmds, i, 1);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return 1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int client_dict_connect(struct client_dict *dict, const char **error_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen const char *query, *error;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->conn.conn.fd_in != -1)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return 0;
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen if (dict->last_failed_connect == ioloop_time) {
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen /* Try again later */
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen *error_r = dict->last_connect_error;
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen return -1;
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen }
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (connection_client_connect(&dict->conn.conn) < 0) {
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen dict->last_failed_connect = ioloop_time;
87e603100685f9eb7faf995d2600edd0a578dd0cTimo Sirainen if (errno == EACCES) {
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen error = eacces_error_get("net_connect_unix",
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen dict->conn.conn.name);
87e603100685f9eb7faf995d2600edd0a578dd0cTimo Sirainen } else {
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen error = t_strdup_printf(
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "net_connect_unix(%s) failed: %m", dict->conn.conn.name);
87e603100685f9eb7faf995d2600edd0a578dd0cTimo Sirainen }
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen i_free(dict->last_connect_error);
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen dict->last_connect_error = i_strdup(error);
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen *error_r = error;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen query = t_strdup_printf("%c%u\t%u\t%d\t%s\t%s\n",
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen DICT_PROTOCOL_CMD_HELLO,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen DICT_CLIENT_PROTOCOL_MAJOR_VERSION,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen DICT_CLIENT_PROTOCOL_MINOR_VERSION,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen dict->value_type, dict->username, dict->uri);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen o_stream_nsend_str(dict->conn.conn.output, query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_add_timeout(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_abort_commands(struct client_dict *dict, const char *reason)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ARRAY(struct client_dict_cmd *) cmds_copy;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *const *cmdp;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* abort all commands */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen t_array_init(&cmds_copy, array_count(&dict->cmds));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_append_array(&cmds_copy, &dict->cmds);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_clear(&dict->cmds);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_foreach(&cmds_copy, cmdp) {
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen dict_cmd_callback_error(*cmdp, reason, TRUE);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_cmd_unref(*cmdp);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict, const char *reason)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen struct client_dict_transaction_context *ctx, *next;
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_abort_commands(dict, reason);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* all transactions that have sent BEGIN are no longer valid */
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen for (ctx = dict->transactions; ctx != NULL; ctx = next) {
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen next = ctx->next;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->sent_begin && ctx->error == NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->error = i_strdup(reason);
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen }
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dict->to_idle);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dict->to_requests);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_disconnect(&dict->conn.conn);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainenstatic int client_dict_reconnect(struct client_dict *dict, const char *reason,
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen const char **error_r)
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen{
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen ARRAY(struct client_dict_cmd *) retry_cmds;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen struct client_dict_cmd *const *cmdp, *cmd;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen const char *error;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen int ret;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen t_array_init(&retry_cmds, array_count(&dict->cmds));
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen for (unsigned int i = 0; i < array_count(&dict->cmds); ) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen cmdp = array_idx(&dict->cmds, i);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen if (!(*cmdp)->retry_errors) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen i++;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen } else if ((*cmdp)->iter != NULL &&
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen (*cmdp)->iter->seen_results) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen /* don't retry iteration that already returned
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen something to the caller. otherwise we'd return
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen duplicates. */
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen i++;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen } else {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen array_append(&retry_cmds, cmdp, 1);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen array_delete(&dict->cmds, i, 1);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen }
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen }
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen client_dict_disconnect(dict, reason);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen if (client_dict_connect(dict, error_r) < 0) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen reason = t_strdup_printf("%s - reconnect failed: %s",
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen reason, *error_r);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen array_foreach(&retry_cmds, cmdp) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen dict_cmd_callback_error(*cmdp, reason, TRUE);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen client_dict_cmd_unref(*cmdp);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen }
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen return -1;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen }
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen if (array_count(&retry_cmds) == 0)
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen return 0;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen i_warning("%s - reconnected", reason);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen ret = 0; error = "";
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen array_foreach(&retry_cmds, cmdp) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen cmd = *cmdp;
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen cmd->reconnected = TRUE;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmd->async_id = 0;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen /* if it fails again, don't retry anymore */
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen cmd->retry_errors = FALSE;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen if (ret < 0) {
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen dict_cmd_callback_error(cmd, error, TRUE);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen client_dict_cmd_unref(cmd);
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen } else if (!client_dict_cmd_send(dict, &cmd, &error))
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen ret = -1;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen }
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen return ret;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen}
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void dict_conn_destroy(struct connection *_conn)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_connection *conn = (struct dict_connection *)_conn;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(conn->dict, connection_disconnect_reason(_conn));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic const struct connection_settings dict_conn_set = {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen .input_max_size = (size_t)-1,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen .output_max_size = (size_t)-1,
b11e9673b057d18c21c683ab17ee7350b9455ddeTimo Sirainen .unix_client_connect_msecs = 1000,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen .client = TRUE
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen};
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic const struct connection_vfuncs dict_conn_vfuncs = {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen .destroy = dict_conn_destroy,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen .input_line = dict_conn_input_line
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen};
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
10399559650f552a23949772be79eb6a80198c5aTimo Sirainenstatic int
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenclient_dict_init(struct dict *driver, const char *uri,
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen const struct dict_settings *set,
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen struct dict **dict_r, const char **error_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct ioloop *old_ioloop = current_ioloop;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *p, *dest_uri, *path;
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen unsigned int idle_msecs = DICT_CLIENT_DEFAULT_TIMEOUT_MSECS;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen unsigned int warn_slow_msecs = DICT_CLIENT_DEFAULT_WARN_SLOW_MSECS;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen /* uri = [idle_msecs=<n>:] [warn_slow_msecs=<n>:] [<path>] ":" <uri> */
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen for (;;) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen if (strncmp(uri, "idle_msecs=", 11) == 0) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen p = strchr(uri+11, ':');
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen if (p == NULL) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen *error_r = t_strdup_printf("Invalid URI: %s", uri);
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen return -1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen }
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen if (str_to_uint(t_strdup_until(uri+11, p), &idle_msecs) < 0) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen *error_r = "Invalid idle_msecs";
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen return -1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen }
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen uri = p+1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen } else if (strncmp(uri, "warn_slow_msecs=", 16) == 0) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen p = strchr(uri+11, ':');
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen if (p == NULL) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen *error_r = t_strdup_printf("Invalid URI: %s", uri);
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen return -1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen }
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen if (str_to_uint(t_strdup_until(uri+16, p), &warn_slow_msecs) < 0) {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen *error_r = "Invalid warn_slow_msecs";
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen return -1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen }
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen uri = p+1;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen } else {
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen break;
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen }
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dest_uri = strchr(uri, ':');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (dest_uri == NULL) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Invalid URI: %s", uri);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict_connections == NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_connections = connection_list_init(&dict_conn_set,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen &dict_conn_vfuncs);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict = i_new(struct client_dict, 1);
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen dict->dict = *driver;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->conn.dict = dict;
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen dict->value_type = set->value_type;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->username = i_strdup(set->username);
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen dict->idle_msecs = idle_msecs;
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen dict->warn_slow_msecs = warn_slow_msecs;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_array_init(&dict->cmds, 32);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen if (uri[0] == ':') {
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* default path */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen path = t_strconcat(set->base_dir,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "/"DEFAULT_DICT_SERVER_SOCKET_FNAME, NULL);
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen } else if (uri[0] == '/') {
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* absolute path */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen path = t_strdup_until(uri, dest_uri);
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen } else {
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* relative path to base_dir */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen path = t_strconcat(set->base_dir, "/",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen t_strdup_until(uri, dest_uri), NULL);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_init_client_unix(dict_connections, &dict->conn.conn, path);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->uri = i_strdup(dest_uri + 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->ioloop = io_loop_create();
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen dict->wait_timer = io_wait_timer_add();
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_set_current(old_ioloop);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen *dict_r = &dict->dict;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen return 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_deinit(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct ioloop *old_ioloop = current_ioloop;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(dict, "Deinit");
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_deinit(&dict->conn.conn);
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen io_wait_timer_remove(&dict->wait_timer);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
29dcd138546179e55e4dbcd3c256ba2fd6726e27Timo Sirainen i_assert(dict->transactions == NULL);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_assert(array_count(&dict->cmds) == 0);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_set_current(dict->ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_destroy(&dict->ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_set_current(old_ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_free(&dict->cmds);
98b7ea1744aecc52750f1dfb0d8ed6f9646b4605Timo Sirainen i_free(dict->last_connect_error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(dict->username);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(dict->uri);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict_connections->connections == NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_list_deinit(&dict_connections);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainenstatic void client_dict_wait(struct dict *_dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (array_count(&dict->cmds) == 0)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
7e74fadc6668d85c2bfd630f215770808d73d1a3Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->prev_ioloop = current_ioloop;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_set_current(dict->ioloop);
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen dict_switch_ioloop(_dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen while (array_count(&dict->cmds) > 0)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_run(dict->ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_set_current(dict->prev_ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->prev_ioloop = NULL;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen dict_switch_ioloop(_dict);
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen}
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainenstatic bool client_dict_switch_ioloop(struct dict *_dict)
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen{
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen dict->last_timer_switch_usecs =
d640b628f27c9bbcbf6fe902b257002a3f0da57bTimo Sirainen io_wait_timer_get_usecs(dict->wait_timer);
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen dict->wait_timer = io_wait_timer_move(&dict->wait_timer);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->to_idle != NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->to_idle = io_loop_move_timeout(&dict->to_idle);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (dict->to_requests != NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->to_requests = io_loop_move_timeout(&dict->to_requests);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_switch_ioloop(&dict->conn.conn);
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen return array_count(&dict->cmds) > 0;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainenstatic const char *dict_wait_warnings(const struct client_dict_cmd *cmd)
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen{
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen int global_ioloop_msecs = (ioloop_global_wait_usecs -
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen cmd->start_global_ioloop_usecs + 999) / 1000;
6d5a7004a7c0b528b7ba05b2656bea80b3f2743dTimo Sirainen int dict_ioloop_msecs = (io_wait_timer_get_usecs(cmd->dict->wait_timer) -
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen cmd->start_dict_ioloop_usecs + 999) / 1000;
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen int other_ioloop_msecs = global_ioloop_msecs - dict_ioloop_msecs;
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen int lock_msecs = (file_lock_wait_get_total_usecs() -
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen cmd->start_lock_usecs + 999) / 1000;
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen return t_strdup_printf(
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen "%d.%03d in dict wait, %d.%03d in other ioloops, %d.%03d in locks",
e33462704d38d05c4109929da4923794f699e3ccTimo Sirainen dict_ioloop_msecs/1000, dict_ioloop_msecs%1000,
e55b5cf82e6d109c658e0b5049cae1ba8edd3b91Timo Sirainen other_ioloop_msecs/1000, other_ioloop_msecs%1000,
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen lock_msecs/1000, lock_msecs%1000);
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen}
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainenstatic const char *
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainendict_warnings_sec(const struct client_dict_cmd *cmd, int msecs,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen const char *const *extra_args)
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen{
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen string_t *str = t_str_new(64);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen struct timeval tv_start, tv_end;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen unsigned int tv_start_usec, tv_end_usec;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_printfa(str, "%d.%03d secs (%s", msecs/1000, msecs%1000,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen dict_wait_warnings(cmd));
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen if (cmd->reconnected) {
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen int reconnected_msecs =
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen timeval_diff_msecs(&ioloop_timeval,
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen &cmd->dict->conn.conn.connect_started);
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen str_printfa(str, ", reconnected %u.%03u secs ago",
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen reconnected_msecs/1000, reconnected_msecs%1000);
d485968ffb1b2456452d79eeda33abeb1bdd5733Timo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->async_id != 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen int async_reply_msecs =
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen timeval_diff_msecs(&ioloop_timeval, &cmd->async_id_received_time);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen str_printfa(str, ", async-id reply %u.%03u secs ago",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen async_reply_msecs/1000, async_reply_msecs%1000);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
cacaa94d258a1f1dd5630e64771186b73813648cTimo Sirainen if (extra_args != NULL &&
cacaa94d258a1f1dd5630e64771186b73813648cTimo Sirainen str_array_length(extra_args) >= 4 &&
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_to_time(extra_args[0], &tv_start.tv_sec) == 0 &&
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_to_uint(extra_args[1], &tv_start_usec) == 0 &&
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_to_time(extra_args[2], &tv_end.tv_sec) == 0 &&
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_to_uint(extra_args[3], &tv_end_usec) == 0) {
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen tv_start.tv_usec = tv_start_usec;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen tv_end.tv_usec = tv_end_usec;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen int server_msecs_since_start =
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &tv_start);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen int server_msecs = timeval_diff_msecs(&tv_end, &tv_start);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_printfa(str, ", started on dict-server %u.%03d secs ago, "
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen "took %u.%03d secs",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen server_msecs_since_start/1000,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen server_msecs_since_start%1000,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen server_msecs/1000, server_msecs%1000);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen }
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_append_c(str, ')');
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen return str_c(str);
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen}
87e7fc1f2804c6f2ae43952def1f30b8cdf00826Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainenclient_dict_lookup_async_callback(struct client_dict_cmd *cmd,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen enum dict_protocol_reply reply,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *value,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen const char *const *extra_args,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *error,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen bool disconnected ATTR_UNUSED)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = cmd->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_lookup_result result;
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen const char *const values[] = { value, NULL };
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.ret = -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = error;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen } else switch (reply) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_OK:
542d7a4afa3d7d8686ebdba691ad02d1c2e99452Timo Sirainen result.value = value;
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen result.values = values;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.ret = 1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen case DICT_PROTOCOL_REPLY_MULTI_OK:
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen result.values = t_strsplit_tabescaped(value);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen result.value = result.values[0];
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen result.ret = 1;
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_NOTFOUND:
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.ret = 0;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_FAIL:
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen result.error = value[0] == '\0' ? "dict-server returned failure" :
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen t_strdup_printf("dict-server returned failure: %s",
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.ret = -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen default:
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = t_strdup_printf(
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen "dict-client: Invalid lookup '%s' reply: %c%s",
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen cmd->query, reply, value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(dict, result.error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.ret = -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &cmd->start_time);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen if (result.error != NULL) {
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen /* include timing info always in error messages */
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen result.error = t_strdup_printf("%s (reply took %s)",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen result.error, dict_warnings_sec(cmd, diff, extra_args));
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen } else if (!cmd->background &&
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen diff >= (int)dict->warn_slow_msecs) {
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen i_warning("read(%s): dict lookup took %s: %s",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen dict->conn.conn.name, dict_warnings_sec(cmd, diff, extra_args),
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen cmd->query);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen }
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_pre_api_callback(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.lookup(&result, cmd->api_callback.context);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_post_api_callback(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_lookup_async(struct dict *_dict, const char *key,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_lookup_callback_t *callback, void *context)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd;
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char *query;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%s", DICT_PROTOCOL_CMD_LOOKUP,
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen str_tabescape(key));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_lookup_async_callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.lookup = callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.context = context;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->retry_errors = TRUE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_cmd_send(dict, &cmd, NULL);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainenstruct client_dict_sync_lookup {
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen char *error;
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi char *value;
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi int ret;
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen};
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_lookup_callback(const struct dict_lookup_result *result,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen void *context)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen struct client_dict_sync_lookup *lookup = context;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi lookup->ret = result->ret;
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen if (result->ret == -1)
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen lookup->error = i_strdup(result->error);
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi else if (result->ret == 1)
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi lookup->value = i_strdup(result->value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic int client_dict_lookup(struct dict *_dict, pool_t pool, const char *key,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char **value_r, const char **error_r)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen struct client_dict_sync_lookup lookup;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&lookup);
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi lookup.ret = -2;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen client_dict_lookup_async(_dict, key, client_dict_lookup_callback, &lookup);
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi if (lookup.ret == -2)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_wait(_dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi switch (lookup.ret) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case -1:
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen *error_r = t_strdup(lookup.error);
48aee87c1ce3b3cd10d53f61b4665da81ef6623bTimo Sirainen i_free(lookup.error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return -1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case 0:
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi i_assert(lookup.value == NULL);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = NULL;
7e74fadc6668d85c2bfd630f215770808d73d1a3Timo Sirainen return 0;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case 1:
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi *value_r = p_strdup(pool, lookup.value);
4f051c3082080b9d69ef12c3720c683cff34b0daAki Tuomi i_free(lookup.value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return 1;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_unreached();
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_iterate_free(struct client_dict_iterate_context *ctx)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (!ctx->deinit || !ctx->finished)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(ctx->error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_free(ctx);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_iter_api_callback(struct client_dict_iterate_context *ctx,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen struct client_dict_cmd *cmd,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen const char *const *extra_args)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen struct client_dict *dict = cmd->dict;
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->deinit) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* iterator was already deinitialized */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen if (ctx->finished) {
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &cmd->start_time);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen if (ctx->error != NULL) {
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen /* include timing info always in error messages */
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen char *new_error = i_strdup_printf("%s (reply took %s)",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen ctx->error, dict_warnings_sec(cmd, diff, extra_args));
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen i_free(ctx->error);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen ctx->error = new_error;
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen } else if (!cmd->background &&
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen diff >= (int)dict->warn_slow_msecs) {
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen i_warning("read(%s): dict iteration took %s: %s",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen dict->conn.conn.name, dict_warnings_sec(cmd, diff, extra_args),
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen cmd->query);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen }
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->ctx.async_callback != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_pre_api_callback(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->ctx.async_callback(ctx->ctx.async_context);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_post_api_callback(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* synchronous lookup */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen io_loop_stop(dict->ioloop);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen}
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainenclient_dict_iter_async_callback(struct client_dict_cmd *cmd,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen enum dict_protocol_reply reply,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *value,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *const *extra_args,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *error,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen bool disconnected ATTR_UNUSED)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_iterate_context *ctx = cmd->iter;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = cmd->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_iter_result *result;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *iter_key = NULL, *iter_value = NULL;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen if (ctx->deinit) {
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen cmd->background = TRUE;
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen client_dict_cmd_backgrounded(dict);
878c4d5eed3307a4018595ded0f79424e9fc1a0dTimo Sirainen }
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* failed */
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen } else switch (reply) {
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen case DICT_PROTOCOL_REPLY_ITER_FINISHED:
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* end of iteration */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->finished = TRUE;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen client_dict_iter_api_callback(ctx, cmd, extra_args);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_iterate_free(ctx);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_OK:
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* key \t value */
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen iter_key = value;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen iter_value = extra_args[0];
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen extra_args++;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
7e74fadc6668d85c2bfd630f215770808d73d1a3Timo Sirainen case DICT_PROTOCOL_REPLY_FAIL:
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen error = t_strdup_printf("dict-server returned failure: %s", value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
7e74fadc6668d85c2bfd630f215770808d73d1a3Timo Sirainen default:
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen if (iter_value == NULL && error == NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* broken protocol */
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen error = t_strdup_printf("dict client (%s) sent broken iterate reply: %c%s",
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen dict->conn.conn.name, reply, value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(dict, error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->error == NULL)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->error = i_strdup(error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->finished = TRUE;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen client_dict_iter_api_callback(ctx, cmd, extra_args);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_iterate_free(ctx);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->unfinished = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->deinit) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* iterator was already deinitialized */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result = array_append_space(&ctx->results);
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen result->key = p_strdup(ctx->results_pool, iter_key);
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen result->value = p_strdup(ctx->results_pool, iter_value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen client_dict_iter_api_callback(ctx, cmd, NULL);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic struct dict_iterate_context *
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenclient_dict_iterate_init(struct dict *_dict, const char *const *paths,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_iterate_flags flags)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_iterate_context, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->ctx.dict = _dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->results_pool = pool_alloconly_create("client dict iteration", 512);
980b0dbdcbeed1a15fdbf4ec1d00352d71a66c5dTimo Sirainen ctx->flags = flags;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen ctx->paths = p_strarray_dup(system_pool, paths);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_array_init(&ctx->results, 64);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen return &ctx->ctx;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen}
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainenstatic void
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainenclient_dict_iterate_cmd_send(struct client_dict_iterate_context *ctx)
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen{
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen struct client_dict_cmd *cmd;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen unsigned int i;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen string_t *query = t_str_new(256);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen /* we can't do this query in _iterate_init(), because
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen _set_limit() hasn't been called yet at that point. */
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(query, "%c%d\t%"PRIu64, DICT_PROTOCOL_CMD_ITERATE,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi ctx->flags, ctx->ctx.max_rows);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen for (i = 0; ctx->paths[i] != NULL; i++) {
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen str_append_c(query, '\t');
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen str_append(query, str_tabescape(ctx->paths[i]));
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, str_c(query));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->iter = ctx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_iter_async_callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->retry_errors = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_cmd_send(dict, &cmd, NULL);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic bool client_dict_iterate(struct dict_iterate_context *_ctx,
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen const char **key_r, const char **value_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_iterate_context *)_ctx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const struct client_dict_iter_result *results;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen unsigned int count;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->ctx.has_more = FALSE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen results = array_get(&ctx->results, &count);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (ctx->result_idx < count) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen *key_r = results[ctx->result_idx].key;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen *value_r = results[ctx->result_idx].value;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->ctx.has_more = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->result_idx++;
8604a0675d3fa7986b872233fc7eb68068e9b80aTimo Sirainen ctx->seen_results = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return TRUE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen if (!ctx->cmd_sent) {
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen ctx->cmd_sent = TRUE;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen client_dict_iterate_cmd_send(ctx);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen return client_dict_iterate(_ctx, key_r, value_r);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->ctx.has_more = !ctx->finished;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->result_idx = 0;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_clear(&ctx->results);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen p_clear(ctx->results_pool);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
980b0dbdcbeed1a15fdbf4ec1d00352d71a66c5dTimo Sirainen if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0 && ctx->ctx.has_more) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_wait(_ctx->dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return client_dict_iterate(_ctx, key_r, value_r);
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return FALSE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainenstatic int client_dict_iterate_deinit(struct dict_iterate_context *_ctx,
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char **error_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_iterate_context *)_ctx;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen int ret = ctx->error != NULL ? -1 : 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->deinit = TRUE;
9e7a30991415f714b609f650105596371a58216dTimo Sirainen
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen *error_r = t_strdup(ctx->error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen array_free(&ctx->results);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen pool_unref(&ctx->results_pool);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen i_free(ctx->paths);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_iterate_free(ctx);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic struct dict_transaction_context *
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_init(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_transaction_context, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->ctx.dict = _dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->id = ++dict->transaction_id_counter;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_PREPEND(&dict->transactions, ctx);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return &ctx->ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainenstatic void
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainenclient_dict_transaction_free(struct client_dict_transaction_context **_ctx)
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen{
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen struct client_dict_transaction_context *ctx = *_ctx;
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen *_ctx = NULL;
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen i_free(ctx->first_query);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen i_free(ctx->error);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen i_free(ctx);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen}
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_transaction_commit_callback(struct client_dict_cmd *cmd,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen enum dict_protocol_reply reply,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *value,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *const *extra_args,
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *error, bool disconnected)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = cmd->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_commit_result result = {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen .ret = DICT_COMMIT_RET_FAILED, .error = NULL
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen };
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen i_assert(cmd->trans != NULL);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* failed */
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen if (disconnected)
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen result.ret = DICT_COMMIT_RET_WRITE_UNCERTAIN;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = error;
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen } else switch (reply) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_OK:
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen result.ret = DICT_COMMIT_RET_OK;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_NOTFOUND:
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen result.ret = DICT_COMMIT_RET_NOTFOUND;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen case DICT_PROTOCOL_REPLY_WRITE_UNCERTAIN:
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen result.ret = DICT_COMMIT_RET_WRITE_UNCERTAIN;
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen /* fallthrough */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen case DICT_PROTOCOL_REPLY_FAIL: {
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen /* value contains the obsolete trans_id */
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen const char *error = extra_args[0];
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = t_strdup_printf("dict-server returned failure: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error != NULL ? t_str_tabunescape(error) : "");
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen if (error != NULL)
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen extra_args++;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
7e74fadc6668d85c2bfd630f215770808d73d1a3Timo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen default:
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen result.ret = DICT_COMMIT_RET_FAILED;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = t_strdup_printf(
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen "dict-client: Invalid commit reply: %c%s",
fc494f157828dee9bb9885dd3630e9b7b45cdb25Timo Sirainen reply, value);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(dict, result.error);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen break;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen }
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &cmd->start_time);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen if (result.error != NULL) {
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen /* include timing info always in error messages */
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen result.error = t_strdup_printf("%s (reply took %s)",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen result.error, dict_warnings_sec(cmd, diff, extra_args));
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen } else if (!cmd->background && !cmd->trans->ctx.no_slowness_warning &&
2525acc19ab4c8ce64c063a5be8e6b8d198a9fbeTimo Sirainen diff >= (int)dict->warn_slow_msecs) {
9578698c44322dad310a9756f3b4dee8e7de646aTimo Sirainen i_warning("read(%s): dict commit took %s: "
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen "%s (%u commands, first: %s)",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen dict->conn.conn.name, dict_warnings_sec(cmd, diff, extra_args),
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen cmd->query, cmd->trans->query_count,
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen cmd->trans->first_query);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen }
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen client_dict_transaction_free(&cmd->trans);
5d234d36b44965f623246520ada9bea02bbf746fTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_pre_api_callback(dict);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.commit(&result, cmd->api_callback.context);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_post_api_callback(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainenstatic void
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_commit(struct dict_transaction_context *_ctx,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen bool async,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_transaction_commit_callback_t *callback,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen void *context)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_cmd *cmd;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char *query;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen DLLIST_REMOVE(&dict->transactions, ctx);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (ctx->sent_begin && ctx->error == NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u", DICT_PROTOCOL_CMD_COMMIT, ctx->id);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, query);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen cmd->trans = ctx;
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_transaction_commit_callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.commit = callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.context = context;
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen if (callback == dict_transaction_commit_async_noop_callback)
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen cmd->background = TRUE;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (client_dict_cmd_send(dict, &cmd, NULL)) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (!async)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_wait(_ctx->dict);
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen }
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else if (ctx->error != NULL) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* already failed */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_commit_result result = {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen .ret = DICT_COMMIT_RET_FAILED, .error = ctx->error
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen };
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen callback(&result, context);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen client_dict_transaction_free(&ctx);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* nothing changed */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_commit_result result = {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen .ret = DICT_COMMIT_RET_OK, .error = NULL
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen };
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen callback(&result, context);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen client_dict_transaction_free(&ctx);
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen }
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen client_dict_add_timeout(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_rollback(struct dict_transaction_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen if (ctx->sent_begin) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u", DICT_PROTOCOL_CMD_ROLLBACK,
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen ctx->id);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen }
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_REMOVE(&dict->transactions, ctx);
56558eb46c396db9c7a0cfd89413b1c50b126b7eTimo Sirainen client_dict_transaction_free(&ctx);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_set(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *key, const char *value)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen const char *query;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u\t%s\t%s",
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen DICT_PROTOCOL_CMD_SET, ctx->id,
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen str_tabescape(key),
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen str_tabescape(value));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenstatic void client_dict_unset(struct dict_transaction_context *_ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key)
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen{
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen struct client_dict_transaction_context *ctx =
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen (struct client_dict_transaction_context *)_ctx;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen const char *query;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u\t%s",
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen DICT_PROTOCOL_CMD_UNSET, ctx->id,
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen str_tabescape(key));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen}
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_atomic_inc(struct dict_transaction_context *_ctx,
a1295ce772f4765320a11a572595ce8eff37c343Timo Sirainen const char *key, long long diff)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen const char *query;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u\t%s\t%lld",
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen DICT_PROTOCOL_CMD_ATOMIC_INC,
cbe2d47fda811fc56ba59cb2811c3fc26033b03cTimo Sirainen ctx->id, str_tabescape(key), diff);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainenstatic void client_dict_set_timestamp(struct dict_transaction_context *_ctx,
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen const struct timespec *ts)
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen{
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen struct client_dict_transaction_context *ctx =
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen (struct client_dict_transaction_context *)_ctx;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen const char *query;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen query = t_strdup_printf("%c%u\t%s\t%u",
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen DICT_PROTOCOL_CMD_TIMESTAMP,
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen ctx->id, dec2str(ts->tv_sec),
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen (unsigned int)ts->tv_nsec);
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen client_dict_send_transaction_query(ctx, query);
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen}
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenstruct dict dict_driver_client = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .name = "proxy",
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen {
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .init = client_dict_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .deinit = client_dict_deinit,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .wait = client_dict_wait,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .lookup = client_dict_lookup,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .iterate_init = client_dict_iterate_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .iterate = client_dict_iterate,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .iterate_deinit = client_dict_iterate_deinit,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_init = client_dict_transaction_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_commit = client_dict_transaction_commit,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_rollback = client_dict_transaction_rollback,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .set = client_dict_set,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .unset = client_dict_unset,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .atomic_inc = client_dict_atomic_inc,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .lookup_async = client_dict_lookup_async,
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen .switch_ioloop = client_dict_switch_ioloop,
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen .set_timestamp = client_dict_set_timestamp,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};