dict-client.c revision 1cfe369d1278a9e2e6cc2e46103db48c493e1f21
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
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. */
98da0024e7340e036f0aa9371e9400176df18ebfTimo Sirainen/* Abort dict lookup after this many seconds. */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#define DICT_CLIENT_REQUEST_TIMEOUT_MSECS 30000
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen/* Log a warning if dict lookup takes longer than this many milliseconds. */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen#define DICT_CLIENT_REQUEST_WARN_TIMEOUT_MSECS 5000
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *transactions;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ARRAY(struct client_dict_iter_result) results;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *prev, *next;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int id;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic struct connection_list *dict_connections;
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int client_dict_connect(struct client_dict *dict, const char **error_r);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict, const char *reason);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_init(struct client_dict *dict, const char *query)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_cmd_ref(struct client_dict_cmd *cmd)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic bool client_dict_cmd_unref(struct client_dict_cmd *cmd)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void dict_pre_api_callback(struct client_dict *dict)
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 Sirainenstatic void dict_post_api_callback(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* stop client_dict_wait() */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainendict_cmd_callback_line(struct client_dict_cmd *cmd, const char *line)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainendict_cmd_callback_error(struct client_dict_cmd *cmd, const char *error)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_input_timeout(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &dict->last_input);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "Timeout: No input from dict for %u.%03u secs",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_query_send(struct client_dict *dict, const char *query)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = o_stream_sendv(dict->conn.conn.output, iov, 2);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_cmd_send(struct client_dict *dict, struct client_dict_cmd **_cmd,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const char **error_r)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* we're no longer idling. even with no_replies=TRUE we're going to
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ret = client_dict_cmd_query_send(dict, cmd->query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error = t_strdup_printf("write(%s) failed: %s", dict->conn.conn.name,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* Reconnect and try again. */
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 /* just send and forget */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else if (ret < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen timeout_add(DICT_CLIENT_REQUEST_TIMEOUT_MSECS,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_transaction_send_begin(struct client_dict_transaction_context *ctx)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
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);
e13bef0a49ee60e4886967b331a7f7d5c96377ccTimo Sirainen if (!client_dict_cmd_send(dict, &cmd, &error)) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_send_transaction_query(struct client_dict_transaction_context *ctx,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (!client_dict_cmd_send(dict, &cmd, &error))
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic bool client_dict_is_finished(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return dict->transactions == NULL && array_count(&dict->cmds) == 0;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_timeout(struct client_dict *dict)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen client_dict_disconnect(dict, "Idle disconnection");
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_add_timeout(struct client_dict *dict)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic int dict_conn_input_line(struct connection *_conn, const char *line)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_connection *conn = (struct dict_connection *)_conn;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen unsigned int count;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen i_error("%s: Received reply without pending commands: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen finished = dict_cmd_callback_line(cmds[0], line);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* disconnected during command handling */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* more lines needed for this command */
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &cmds[0]->start_time);
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen if (diff < DICT_CLIENT_REQUEST_WARN_TIMEOUT_MSECS)
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen else if (cmds[0]->commit_query_human != NULL) {
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen i_warning("read(%s): dict commit took %u.%03u seconds: %s",
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen i_warning("read(%s): dict %s took %u.%03u seconds: %s",
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainen dict->conn.conn.name, type, diff/1000, diff % 1000,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int client_dict_connect(struct client_dict *dict, const char **error_r)
fc0c06ee7b1e5c29a3faabd05f40fa0d26785dffTimo Sirainen if (dict->last_failed_connect == ioloop_time) {
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen /* Try again later */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen if (connection_client_connect(&dict->conn.conn) < 0) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "net_connect_unix(%s) failed: %m", dict->conn.conn.name);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen query = t_strdup_printf("%c%u\t%u\t%d\t%s\t%s\n",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen o_stream_nsend_str(dict->conn.conn.output, query);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_abort_commands(struct client_dict *dict, const char *reason)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* abort all commands */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen t_array_init(&cmds_copy, array_count(&dict->cmds));
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict, const char *reason)
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen struct client_dict_transaction_context *ctx, *next;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* all transactions that have sent BEGIN are no longer valid */
b529524e924da0d86f8b7f0fa3c9e3e3f763a9f3Timo Sirainen for (ctx = dict->transactions; ctx != NULL; ctx = next) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void dict_conn_destroy(struct connection *_conn)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_connection *conn = (struct dict_connection *)_conn;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_disconnect(conn->dict, connection_disconnect_reason(_conn));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic const struct connection_settings dict_conn_set = {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic const struct connection_vfuncs dict_conn_vfuncs = {
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenclient_dict_init(struct dict *driver, const char *uri,
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen unsigned int idle_msecs = DICT_CLIENT_DEFAULT_TIMEOUT_MSECS;
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen /* uri = [idle_msecs=<n>:] [<path>] ":" <uri> */
09cd60cebc01b2b25ada824f3d9f877d5efd8272Timo Sirainen *error_r = t_strdup_printf("Invalid URI: %s", uri);
567ace1f60eca983acbc9b42d7569a5c16e8c3ecTimo Sirainen if (str_to_uint(t_strdup_until(uri+11, p), &idle_msecs) < 0) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Invalid URI: %s", uri);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_connections = connection_list_init(&dict_conn_set,
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* default path */
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* absolute path */
02a0277d897dbf5172937158f3d828f981ff230dTimo Sirainen /* relative path to base_dir */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen connection_init_client_unix(dict_connections, &dict->conn.conn, path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_deinit(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainenstatic void client_dict_wait(struct dict *_dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainenstatic bool client_dict_switch_ioloop(struct dict *_dict)
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->to_idle = io_loop_move_timeout(&dict->to_idle);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict->to_requests = io_loop_move_timeout(&dict->to_requests);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_lookup_async_callback(struct client_dict_cmd *cmd, const char *line,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else switch (*line) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = line[1] == '\0' ? "dict-server returned failure" :
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen t_strdup_printf("dict-server returned failure: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "dict-client: Invalid lookup '%s' reply: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.lookup(&result, cmd->api_callback.context);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_lookup_async(struct dict *_dict, const char *key,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen dict_lookup_callback_t *callback, void *context)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%s", DICT_PROTOCOL_CMD_LOOKUP,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_lookup_async_callback;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_lookup_callback(const struct dict_lookup_result *result,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct dict_lookup_result *result_copy = context;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic int client_dict_lookup(struct dict *_dict, pool_t pool, const char *key,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_lookup_async(_dict, key, client_dict_lookup_callback, &result);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenstatic void client_dict_iterate_free(struct client_dict_iterate_context *ctx)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_iter_api_callback(struct client_dict_iterate_context *ctx,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* iterator was already deinitialized */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->ctx.async_callback(ctx->ctx.async_context);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* synchronous lookup */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_iter_async_callback(struct client_dict_cmd *cmd, const char *line,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen struct client_dict_iterate_context *ctx = cmd->iter;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else switch (*line) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* end of iteration */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* key \t value */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error = t_strdup_printf("dict-server returned failure: %s", line+1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* broken protocol */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error = t_strdup_printf("dict client (%s) sent broken iterate reply: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* stop client_dict_wait() */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* iterator was already deinitialized */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result->key = p_strdup(ctx->results_pool, t_str_tabunescape(key));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result->value = p_strdup(ctx->results_pool, t_str_tabunescape(value));
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenclient_dict_iterate_init(struct dict *_dict, const char *const *paths,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen unsigned int i;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_iterate_context, 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->results_pool = pool_alloconly_create("client dict iteration", 512);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen ctx->async = (flags & DICT_ITERATE_FLAG_ASYNC) != 0;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen str_printfa(query, "%c%d", DICT_PROTOCOL_CMD_ITERATE, flags);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd = client_dict_cmd_init(dict, str_c(query));
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_iter_async_callback;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic bool client_dict_iterate(struct dict_iterate_context *_ctx,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen const struct client_dict_iter_result *results;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen unsigned int count;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen return client_dict_iterate(_ctx, key_r, value_r);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainenstatic int client_dict_iterate_deinit(struct dict_iterate_context *_ctx,
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char **error_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_init(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_transaction_context, 1);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainenclient_dict_transaction_commit_callback(struct client_dict_cmd *cmd,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen } else switch (*line) {
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen result.error = t_strdup_printf("dict-server returned failure: %s",
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen error != NULL ? t_str_tabunescape(error) : "");
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen "dict-client: Invalid commit reply: %s", line);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->api_callback.commit(&result, cmd->api_callback.context);
1cfe369d1278a9e2e6cc2e46103db48c493e1f21Timo Sirainenclient_dict_transaction_free(struct client_dict_transaction_context *ctx)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_commit(struct 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 query = t_strdup_printf("%c%u", DICT_PROTOCOL_CMD_COMMIT, ctx->id);
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen cmd->callback = client_dict_transaction_commit_callback;
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen if (callback == dict_transaction_commit_async_noop_callback)
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* already failed */
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen /* nothing changed */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_rollback(struct dict_transaction_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen query = t_strdup_printf("%c%u", DICT_PROTOCOL_CMD_ROLLBACK,
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_set(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenstatic void client_dict_unset(struct dict_transaction_context *_ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key)
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen (struct client_dict_transaction_context *)_ctx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_atomic_inc(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
a7e46c05358b059aad2b90f01e271ba6732c5eeeTimo Sirainen client_dict_send_transaction_query(ctx, query);
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_init = client_dict_transaction_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_commit = client_dict_transaction_commit,