bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "lib.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "array.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "ostream.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "str.h"
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen#include "strescape.h"
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#include "stats-dist.h"
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen#include "time-util.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "dict-client.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "dict-settings.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "dict-connection.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#include "dict-commands.h"
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen#include "main.h"
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen#define DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION 1
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen#define DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION 1
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen#define DICT_OUTPUT_OPTIMAL_SIZE 1024
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstruct dict_cmd_func {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen enum dict_protocol_cmd cmd;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen int (*func)(struct dict_connection_cmd *cmd, const char *line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen};
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstruct dict_connection_cmd {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen const struct dict_cmd_func *cmd;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection *conn;
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen struct timeval start_timeval;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen char *reply;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_iterate_context *iter;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen enum dict_iterate_flags iter_flags;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int async_reply_id;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen unsigned int trans_id; /* obsolete */
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen};
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainenstruct dict_command_stats cmd_stats;
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainenstatic int cmd_iterate_flush(struct dict_connection_cmd *cmd);
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void dict_connection_cmd_free(struct dict_connection_cmd *cmd)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *error;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (cmd->iter != NULL) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&cmd->iter, &error) < 0)
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("dict_iterate() failed: %s", error);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen i_free(cmd->reply);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen if (dict_connection_unref(cmd->conn))
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_connection_continue_input(cmd->conn);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen i_free(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void dict_connection_cmd_remove(struct dict_connection_cmd *cmd)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *const *cmds;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen unsigned int i, count;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmds = array_get(&cmd->conn->cmds, &count);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen for (i = 0; i < count; i++) {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (cmds[i] == cmd) {
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen array_delete(&cmd->conn->cmds, i, 1);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_connection_cmd_free(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen i_unreached();
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void dict_connection_cmds_flush(struct dict_connection *conn)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd, *const *first_cmdp;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(conn->minor_version < DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_connection_ref(conn);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen while (array_count(&conn->cmds) > 0) {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen first_cmdp = array_idx(&conn->cmds, 0);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd = *first_cmdp;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(cmd->async_reply_id == 0);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainen /* we may be able to start outputting iterations now. */
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainen if (cmd->iter != NULL)
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainen (void)cmd_iterate_flush(cmd);
8bb454924c8b4612e4b657e60a860f8f0f3d6054Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (cmd->reply == NULL) {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen /* command not finished yet */
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen break;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen o_stream_nsend_str(conn->output, cmd->reply);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_connection_cmd_remove(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
f6d8250f99520eac003da742a5f34abd2b537c38Timo Sirainen dict_connection_unref_safe(conn);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic void dict_connection_cmd_try_flush(struct dict_connection_cmd **_cmd)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct dict_connection_cmd *cmd = *_cmd;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen *_cmd = NULL;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmds_flush(cmd->conn);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(cmd->async_reply_id != 0);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(cmd->reply != NULL);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen o_stream_nsend_str(cmd->conn->output, t_strdup_printf("%c%u\t%s",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen DICT_PROTOCOL_REPLY_ASYNC_REPLY,
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmd->async_reply_id, cmd->reply));
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_remove(cmd);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen}
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic void dict_connection_cmd_async(struct dict_connection_cmd *cmd)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_UNORDERED_MIN_VERSION)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen i_assert(cmd->async_reply_id == 0);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmd->async_reply_id = ++cmd->conn->async_id_counter;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->async_reply_id == 0)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmd->async_reply_id = ++cmd->conn->async_id_counter;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen o_stream_nsend_str(cmd->conn->output, t_strdup_printf("%c%u\n",
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen DICT_PROTOCOL_REPLY_ASYNC_ID, cmd->async_reply_id));
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen}
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainenstatic void
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainencmd_stats_update(struct dict_connection_cmd *cmd, struct stats_dist *stats)
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen{
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen long long diff;
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen if (!dict_settings->verbose_proctitle)
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen return;
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen diff = timeval_diff_usecs(&ioloop_timeval, &cmd->start_timeval);
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen if (diff < 0)
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen diff = 0;
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_add(stats, diff);
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen dict_proctitle_update_later();
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen}
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainenstatic void
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainendict_cmd_reply_handle_stats(struct dict_connection_cmd *cmd,
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen string_t *str, struct stats_dist *stats)
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen{
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen io_loop_time_refresh();
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen cmd_stats_update(cmd, stats);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION)
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen return;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_printfa(str, "\t%ld\t%u\t%ld\t%u",
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen (long)cmd->start_timeval.tv_sec,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen (unsigned int)cmd->start_timeval.tv_usec,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen (long)ioloop_timeval.tv_sec,
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen (unsigned int)ioloop_timeval.tv_usec);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen}
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainenstatic void
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainencmd_lookup_write_reply(struct dict_connection_cmd *cmd,
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen const char *const *values, string_t *str)
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen{
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen string_t *tmp;
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen i_assert(values[0] != NULL);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_VERSION_MIN_MULTI_OK ||
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen values[1] == NULL) {
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_OK);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_tabescaped(str, values[0]);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen return;
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen }
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen /* the results get double-tabescaped so they end up becoming a single
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen parameter */
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen tmp = t_str_new(128);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen for (unsigned int i = 0; values[i] != NULL; i++) {
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_c(tmp, '\t');
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_tabescaped(tmp, values[i]);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen }
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_MULTI_OK);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen str_append_tabescaped(str, str_c(tmp) + 1);
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen}
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainencmd_lookup_callback(const struct dict_lookup_result *result, void *context)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd = context;
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen string_t *str = t_str_new(128);
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (result->ret > 0) {
217683437468663839ec9bb6c7d2892b98fae4f9Timo Sirainen cmd_lookup_write_reply(cmd, result->values, str);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen } else if (result->ret == 0) {
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_NOTFOUND);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen } else {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen i_error("%s", result->error);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_append_tabescaped(str, result->error);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen dict_cmd_reply_handle_stats(cmd, str, cmd_stats.lookups);
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen str_append_c(str, '\n');
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen
8e1491e4924e3f9fc474a99438b6297b8d1ce1f3Timo Sirainen cmd->reply = i_strdup(str_c(str));
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_try_flush(&cmd);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_lookup(struct dict_connection_cmd *cmd, const char *line)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen /* <key> */
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_async(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_lookup_async(cmd->conn->dict, line, cmd_lookup_callback, cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 1;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainenstatic bool dict_connection_flush_if_full(struct dict_connection *conn)
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen{
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen if (o_stream_get_buffer_used_size(conn->output) >
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen DICT_OUTPUT_OPTIMAL_SIZE) {
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen if (o_stream_flush(conn->output) <= 0) {
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen /* continue later when there's more space
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen in output buffer */
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen o_stream_set_flush_pending(conn->output, TRUE);
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen return FALSE;
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen }
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen /* flushed everything, continue */
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen }
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen return TRUE;
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen}
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_iterate_flush(struct dict_connection_cmd *cmd)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen string_t *str;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *key, *value, *error;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen if (!dict_connection_flush_if_full(cmd->conn))
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen return 0;
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen str = t_str_new(256);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen while (dict_iterate(cmd->iter, &key, &value)) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen str_truncate(str, 0);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->async_reply_id != 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_ASYNC_REPLY);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen str_printfa(str, "%u\t", cmd->async_reply_id);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_OK);
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen str_append_tabescaped(str, key);
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen str_append_c(str, '\t');
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if ((cmd->iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0)
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen str_append_tabescaped(str, value);
6b3c7d7396f8f425da6f9ce665317d5739ace8c4Timo Sirainen str_append_c(str, '\n');
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen o_stream_nsend(cmd->conn->output, str_data(str), str_len(str));
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen if (!dict_connection_flush_if_full(cmd->conn))
1fb0136a1eef1990e24268e0916a998b36149e14Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_iterate_has_more(cmd->iter)) {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen /* wait for the next iteration callback */
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 0;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen str_truncate(str, 0);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&cmd->iter, &error) < 0) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("dict_iterate() failed: %s", error);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen str_printfa(str, "%c%s", DICT_PROTOCOL_REPLY_FAIL, error);
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen }
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen dict_cmd_reply_handle_stats(cmd, str, cmd_stats.iterations);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen str_append_c(str, '\n');
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd->reply = i_strdup(str_c(str));
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return 1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void cmd_iterate_callback(void *context)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd = context;
af298f9a4cc206f5d6c153504de6caa4807231baTimo Sirainen struct dict_connection *conn = cmd->conn;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
af298f9a4cc206f5d6c153504de6caa4807231baTimo Sirainen dict_connection_ref(conn);
af298f9a4cc206f5d6c153504de6caa4807231baTimo Sirainen o_stream_cork(conn->output);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_connection_cmd_output_more(cmd);
af298f9a4cc206f5d6c153504de6caa4807231baTimo Sirainen o_stream_uncork(conn->output);
af298f9a4cc206f5d6c153504de6caa4807231baTimo Sirainen dict_connection_unref_safe(conn);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_iterate(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const char *const *args;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen unsigned int flags;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen uint64_t max_rows;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen args = t_strsplit_tabescaped(line);
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen if (str_array_length(args) < 3 ||
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen str_to_uint(args[0], &flags) < 0 ||
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen str_to_uint64(args[1], &max_rows) < 0) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: ITERATE: broken input");
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_async(cmd);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen /* <flags> <max_rows> <path> */
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen flags |= DICT_ITERATE_FLAG_ASYNC;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen cmd->iter = dict_iterate_init_multiple(cmd->conn->dict, args+2, flags);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd->iter_flags = flags;
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen if (max_rows > 0)
8c0e4118f21c30455d4911fabc4bf50bfaeca712Timo Sirainen dict_iterate_set_limit(cmd->iter, max_rows);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_iterate_set_async_callback(cmd->iter, cmd_iterate_callback, cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_connection_cmd_output_more(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainenstatic struct dict_connection_transaction *
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainendict_connection_transaction_lookup(struct dict_connection *conn,
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen unsigned int id)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen struct dict_connection_transaction *transaction;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen if (!array_is_created(&conn->transactions))
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return NULL;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&conn->transactions, transaction) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (transaction->id == id)
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen return transaction;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return NULL;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainenstatic void
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainendict_connection_transaction_array_remove(struct dict_connection *conn,
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen unsigned int id)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const struct dict_connection_transaction *transactions;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen unsigned int i, count;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen transactions = array_get(&conn->transactions, &count);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen for (i = 0; i < count; i++) {
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen if (transactions[i].id == id) {
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen i_assert(transactions[i].ctx == NULL);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen array_delete(&conn->transactions, i, 1);
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen return;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen i_unreached();
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_begin(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction *trans;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen unsigned int id;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_uint(line, &id) < 0) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: Invalid transaction ID %s", line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_connection_transaction_lookup(cmd->conn, id) != NULL) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: Transaction ID %u already exists", id);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (!array_is_created(&cmd->conn->transactions))
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen i_array_init(&cmd->conn->transactions, 4);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen /* <id> */
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen trans = array_append_space(&cmd->conn->transactions);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen trans->id = id;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen trans->conn = cmd->conn;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen trans->ctx = dict_transaction_begin(cmd->conn->dict);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainenstatic int
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainendict_connection_transaction_lookup_parse(struct dict_connection *conn,
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const char *line,
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction **trans_r)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen unsigned int id;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_uint(line, &id) < 0) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: Invalid transaction ID %s", line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen *trans_r = dict_connection_transaction_lookup(conn, id);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen if (*trans_r == NULL) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: Transaction ID %u doesn't exist", id);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic void
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainencmd_commit_finish(struct dict_connection_cmd *cmd,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const struct dict_commit_result *result, bool async)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen string_t *str = t_str_new(64);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen char chr;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen switch (result->ret) {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen case DICT_COMMIT_RET_OK:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen chr = DICT_PROTOCOL_REPLY_OK;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen case DICT_COMMIT_RET_NOTFOUND:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen chr = DICT_PROTOCOL_REPLY_NOTFOUND;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen case DICT_COMMIT_RET_WRITE_UNCERTAIN:
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen i_assert(result->error != NULL);
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen chr = DICT_PROTOCOL_REPLY_WRITE_UNCERTAIN;
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen break;
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen case DICT_COMMIT_RET_FAILED:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen default:
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_assert(result->error != NULL);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen chr = DICT_PROTOCOL_REPLY_FAIL;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (async)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen str_append_c(str, DICT_PROTOCOL_REPLY_ASYNC_COMMIT);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen str_printfa(str, "%c%u", chr, cmd->trans_id);
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen if (chr != DICT_PROTOCOL_REPLY_OK &&
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen chr != DICT_PROTOCOL_REPLY_NOTFOUND) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen str_append_c(str, '\t');
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen str_append_tabescaped(str, result->error);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen dict_cmd_reply_handle_stats(cmd, str, cmd_stats.commits);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen str_append_c(str, '\n');
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen cmd->reply = i_strdup(str_c(str));
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_connection_transaction_array_remove(cmd->conn, cmd->trans_id);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_try_flush(&cmd);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void cmd_commit_callback(const struct dict_commit_result *result,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen void *context)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd = context;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen cmd_commit_finish(cmd, result, FALSE);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void cmd_commit_callback_async(const struct dict_commit_result *result,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen void *context)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd = context;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen cmd_commit_finish(cmd, result, TRUE);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainenstatic int
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainencmd_commit(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen struct dict_connection_transaction *trans;
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen cmd->trans_id = trans->id;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_async(cmd);
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_transaction_commit_async(&trans->ctx, cmd_commit_callback, cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 1;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainencmd_commit_async(struct dict_connection_cmd *cmd, const char *line)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen struct dict_connection_transaction *trans;
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen cmd->trans_id = trans->id;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_async(cmd);
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_transaction_commit_async(&trans->ctx, cmd_commit_callback_async, cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_rollback(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction *trans;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen dict_transaction_rollback(&trans->ctx);
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_connection_transaction_array_remove(cmd->conn, trans->id);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_set(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction *trans;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const char *const *args;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen /* <id> <key> <value> */
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen args = t_strsplit_tabescaped(line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen if (str_array_length(args) != 3) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: SET: broken input");
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen dict_set(trans->ctx, args[1], args[2]);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_unset(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction *trans;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const char *const *args;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen /* <id> <key> */
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen args = t_strsplit_tabescaped(line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen if (str_array_length(args) != 2) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: UNSET: broken input");
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen dict_unset(trans->ctx, args[1]);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic int cmd_atomic_inc(struct dict_connection_cmd *cmd, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen struct dict_connection_transaction *trans;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen const char *const *args;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen long long diff;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen /* <id> <key> <diff> */
ad0131e97521153d9c4f3419fdd36f19cb76b8fcTimo Sirainen args = t_strsplit_tabescaped(line);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_array_length(args) != 3 ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_llong(args[2], &diff) < 0) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: ATOMIC_INC: broken input");
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen dict_atomic_inc(trans->ctx, args[1], diff);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return 0;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainenstatic int cmd_timestamp(struct dict_connection_cmd *cmd, const char *line)
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen{
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen struct dict_connection_transaction *trans;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen const char *const *args;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen long long tv_sec;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen unsigned int tv_nsec;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen /* <id> <secs> <nsecs> */
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen args = t_strsplit_tabescaped(line);
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen if (str_array_length(args) != 3 ||
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen str_to_llong(args[1], &tv_sec) < 0 ||
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen str_to_uint(args[2], &tv_nsec) < 0) {
18c01c2573243be3eaaf3c584236d865ae3390fdTimo Sirainen i_error("dict client: TIMESTAMP: broken input");
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen return -1;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen }
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen return -1;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen struct timespec ts = {
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen .tv_sec = tv_sec,
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen .tv_nsec = tv_nsec
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen };
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen dict_transaction_set_timestamp(trans->ctx, &ts);
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen return 0;
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen}
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic const struct dict_cmd_func cmds[] = {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_LOOKUP, cmd_lookup },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_ITERATE, cmd_iterate },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_BEGIN, cmd_begin },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_COMMIT, cmd_commit },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_COMMIT_ASYNC, cmd_commit_async },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_ROLLBACK, cmd_rollback },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_SET, cmd_set },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_UNSET, cmd_unset },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { DICT_PROTOCOL_CMD_ATOMIC_INC, cmd_atomic_inc },
345fceae2f430dcad449f2a09598ba1a225116ddTimo Sirainen { DICT_PROTOCOL_CMD_TIMESTAMP, cmd_timestamp },
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen { 0, NULL }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen};
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenstatic const struct dict_cmd_func *dict_command_find(enum dict_protocol_cmd cmd)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen unsigned int i;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen for (i = 0; cmds[i].cmd != '\0'; i++) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen if (cmds[i].cmd == cmd)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return &cmds[i];
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return NULL;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainenint dict_command_input(struct dict_connection *conn, const char *line)
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen const struct dict_cmd_func *cmd_func;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen struct dict_connection_cmd *cmd;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen int ret;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd_func = dict_command_find((enum dict_protocol_cmd)*line);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if (cmd_func == NULL) {
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen i_error("dict client: Unknown command %c", *line);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen return -1;
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen }
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd = i_new(struct dict_connection_cmd, 1);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd->conn = conn;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen cmd->cmd = cmd_func;
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen cmd->start_timeval = ioloop_timeval;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen array_append(&conn->cmds, &cmd, 1);
ac00e30516d93d289c71bd59f338c26693329e67Timo Sirainen dict_connection_ref(conn);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen if ((ret = cmd_func->func(cmd, line + 1)) <= 0) {
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen dict_connection_cmd_remove(cmd);
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return ret;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen return 0;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic bool dict_connection_cmds_try_output_more(struct dict_connection *conn)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct dict_connection_cmd *const *cmdp, *cmd;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen /* only iterators may be returning a lot of data */
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen array_foreach(&conn->cmds, cmdp) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen cmd = *cmdp;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->iter == NULL) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen /* not an iterator */
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen } else if (cmd_iterate_flush(cmd) == 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen /* unfinished */
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen } else {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen dict_connection_cmd_try_flush(&cmd);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen /* cmd should be freed now, restart output */
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return TRUE;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (conn->minor_version < DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen break;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen /* try to flush the rest */
ab2f731c442a693897392f652ebbf9ddde1e5a27Timo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return FALSE;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainenvoid dict_connection_cmds_output_more(struct dict_connection *conn)
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen{
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen while (array_count(&conn->cmds) > 0) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (!dict_connection_cmds_try_output_more(conn))
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen break;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen}
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainenstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen{
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen struct dict_connection_cmd *const *first_cmdp;
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION) {
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen first_cmdp = array_idx(&cmd->conn->cmds, 0);
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen if (*first_cmdp != cmd)
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen return;
1a883718249b8db128a105ee7f03293873f1f9c5Timo Sirainen }
44c54229a117b8dab05eaff9c54ba61fbae9a39fTimo Sirainen (void)dict_connection_cmds_try_output_more(cmd->conn);
1ea214b620715aa8b213c5686383b821e720fe42Timo Sirainen}
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainenvoid dict_commands_init(void)
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen{
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen cmd_stats.lookups = stats_dist_init();
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen cmd_stats.iterations = stats_dist_init();
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen cmd_stats.commits = stats_dist_init();
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen}
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainenvoid dict_commands_deinit(void)
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen{
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_deinit(&cmd_stats.lookups);
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_deinit(&cmd_stats.iterations);
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen stats_dist_deinit(&cmd_stats.commits);
cbe49ba128638e63395aedaa2144087c89835633Timo Sirainen}