dict-commands.c revision 6cfe560af03491c2ea118e9698a145d8a9ee26b2
c28749e97052f09388969427adf7df641cdcdc22kais/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais#include "lib.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "array.h"
968d6dde54d2efa62910a3cf36438325d0b69031krishna#include "ostream.h"
968d6dde54d2efa62910a3cf36438325d0b69031krishna#include "str.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "strescape.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "dict-client.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "dict-settings.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "dict-connection.h"
c28749e97052f09388969427adf7df641cdcdc22kais#include "dict-commands.h"
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais#define DICT_OUTPUT_OPTIMAL_SIZE 1024
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstruct dict_cmd_func {
c28749e97052f09388969427adf7df641cdcdc22kais enum dict_protocol_cmd cmd;
c28749e97052f09388969427adf7df641cdcdc22kais int (*func)(struct dict_connection_cmd *cmd, const char *line);
c28749e97052f09388969427adf7df641cdcdc22kais};
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstruct dict_connection_cmd {
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri const struct dict_cmd_func *cmd;
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection *conn;
c28749e97052f09388969427adf7df641cdcdc22kais char *reply;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_iterate_context *iter;
c28749e97052f09388969427adf7df641cdcdc22kais enum dict_iterate_flags iter_flags;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int trans_id;
c28749e97052f09388969427adf7df641cdcdc22kais};
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd);
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void dict_connection_cmd_free(struct dict_connection_cmd *cmd)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais if (cmd->iter != NULL)
c28749e97052f09388969427adf7df641cdcdc22kais (void)dict_iterate_deinit(&cmd->iter);
c28749e97052f09388969427adf7df641cdcdc22kais i_free(cmd->reply);
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_unref(cmd->conn))
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_continue_input(cmd->conn);
c28749e97052f09388969427adf7df641cdcdc22kais i_free(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void dict_connection_cmd_remove(struct dict_connection_cmd *cmd)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *const *cmds;
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int i, count;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmds = array_get(&cmd->conn->cmds, &count);
c28749e97052f09388969427adf7df641cdcdc22kais for (i = 0; i < count; i++) {
c28749e97052f09388969427adf7df641cdcdc22kais if (cmds[i] == cmd) {
c28749e97052f09388969427adf7df641cdcdc22kais array_delete(&cmd->conn->cmds, i, 1);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmd_free(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return;
c28749e97052f09388969427adf7df641cdcdc22kais }
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna }
c28749e97052f09388969427adf7df641cdcdc22kais i_unreached();
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna}
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void dict_connection_cmds_flush(struct dict_connection *conn)
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna{
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna struct dict_connection_cmd *cmd, *const *first_cmdp;
c28749e97052f09388969427adf7df641cdcdc22kais
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna dict_connection_ref(conn);
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna while (array_count(&conn->cmds) > 0) {
c28749e97052f09388969427adf7df641cdcdc22kais first_cmdp = array_idx(&conn->cmds, 0);
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna cmd = *first_cmdp;
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna if (cmd->reply == NULL) {
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna /* command not finished yet */
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna break;
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna }
2bd70d4be73561631df9cb3d9eb4c65fa94fa665krishna
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_nsend_str(conn->output, cmd->reply);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmd_remove(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_unref_safe(conn);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void
c28749e97052f09388969427adf7df641cdcdc22kaiscmd_lookup_callback(const struct dict_lookup_result *result, void *context)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *cmd = context;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (result->ret > 0) {
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup_printf("%c%s\n",
c28749e97052f09388969427adf7df641cdcdc22kais DICT_PROTOCOL_REPLY_OK, str_tabescape(result->value));
c28749e97052f09388969427adf7df641cdcdc22kais } else if (result->ret == 0) {
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup_printf("%c\n", DICT_PROTOCOL_REPLY_NOTFOUND);
c28749e97052f09388969427adf7df641cdcdc22kais } else {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("%s", result->error);
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup_printf("%c%s\n", DICT_PROTOCOL_REPLY_FAIL,
c28749e97052f09388969427adf7df641cdcdc22kais str_tabescape(result->error));
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmds_flush(cmd->conn);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_lookup(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais /* <key> */
c28749e97052f09388969427adf7df641cdcdc22kais dict_lookup_async(cmd->conn->dict, line, cmd_lookup_callback, cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return 1;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_iterate_flush(struct dict_connection_cmd *cmd)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais string_t *str;
c28749e97052f09388969427adf7df641cdcdc22kais const char *key, *value;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais str = t_str_new(256);
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_cork(cmd->conn->output);
c28749e97052f09388969427adf7df641cdcdc22kais while (dict_iterate(cmd->iter, &key, &value)) {
c28749e97052f09388969427adf7df641cdcdc22kais str_truncate(str, 0);
c28749e97052f09388969427adf7df641cdcdc22kais str_append_c(str, DICT_PROTOCOL_REPLY_OK);
c28749e97052f09388969427adf7df641cdcdc22kais str_append_tabescaped(str, key);
c28749e97052f09388969427adf7df641cdcdc22kais str_append_c(str, '\t');
c28749e97052f09388969427adf7df641cdcdc22kais if ((cmd->iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0)
c28749e97052f09388969427adf7df641cdcdc22kais str_append_tabescaped(str, value);
c28749e97052f09388969427adf7df641cdcdc22kais str_append_c(str, '\n');
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_nsend(cmd->conn->output, str_data(str), str_len(str));
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (o_stream_get_buffer_used_size(cmd->conn->output) >
c28749e97052f09388969427adf7df641cdcdc22kais DICT_OUTPUT_OPTIMAL_SIZE) {
c28749e97052f09388969427adf7df641cdcdc22kais if (o_stream_flush(cmd->conn->output) <= 0) {
c28749e97052f09388969427adf7df641cdcdc22kais /* continue later when there's more space
c28749e97052f09388969427adf7df641cdcdc22kais in output buffer */
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_uncork(cmd->conn->output);
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_set_flush_pending(cmd->conn->output, TRUE);
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais /* flushed everything, continue */
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_iterate_has_more(cmd->iter)) {
c28749e97052f09388969427adf7df641cdcdc22kais /* wait for the next iteration callback */
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais str_truncate(str, 0);
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_iterate_deinit(&cmd->iter) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
c28749e97052f09388969427adf7df641cdcdc22kais str_append_c(str, '\n');
c28749e97052f09388969427adf7df641cdcdc22kais o_stream_uncork(cmd->conn->output);
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup(str_c(str));
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmds_flush(cmd->conn);
c28749e97052f09388969427adf7df641cdcdc22kais return 1;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void cmd_iterate_callback(void *context)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *cmd = context;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmd_output_more(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais}
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishnastatic int cmd_iterate(struct dict_connection_cmd *cmd, const char *line)
efe05f9ecde56550699213909fd4152ef8ef6438krishna{
efe05f9ecde56550699213909fd4152ef8ef6438krishna const char *const *args;
efe05f9ecde56550699213909fd4152ef8ef6438krishna unsigned int flags;
efe05f9ecde56550699213909fd4152ef8ef6438krishna
c28749e97052f09388969427adf7df641cdcdc22kais args = t_strsplit_tabescaped(line);
c28749e97052f09388969427adf7df641cdcdc22kais if (str_array_length(args) < 2 ||
c28749e97052f09388969427adf7df641cdcdc22kais str_to_uint(args[0], &flags) < 0) {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("dict client: ITERATE: broken input");
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais /* <flags> <path> */
c28749e97052f09388969427adf7df641cdcdc22kais flags |= DICT_ITERATE_FLAG_ASYNC;
c28749e97052f09388969427adf7df641cdcdc22kais cmd->iter = dict_iterate_init_multiple(cmd->conn->dict, args+1, flags);
c28749e97052f09388969427adf7df641cdcdc22kais cmd->iter_flags = flags;
c28749e97052f09388969427adf7df641cdcdc22kais dict_iterate_set_async_callback(cmd->iter, cmd_iterate_callback, cmd);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmd_output_more(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return 1;
c28749e97052f09388969427adf7df641cdcdc22kais}
efe05f9ecde56550699213909fd4152ef8ef6438krishna
c28749e97052f09388969427adf7df641cdcdc22kaisstatic struct dict_connection_transaction *
c28749e97052f09388969427adf7df641cdcdc22kaisdict_connection_transaction_lookup(struct dict_connection *conn,
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int id)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *transaction;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (!array_is_created(&conn->transactions))
c28749e97052f09388969427adf7df641cdcdc22kais return NULL;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais array_foreach_modifiable(&conn->transactions, transaction) {
c28749e97052f09388969427adf7df641cdcdc22kais if (transaction->id == id)
c28749e97052f09388969427adf7df641cdcdc22kais return transaction;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais return NULL;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void
c28749e97052f09388969427adf7df641cdcdc22kaisdict_connection_transaction_array_remove(struct dict_connection *conn,
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int id)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais const struct dict_connection_transaction *transactions;
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int i, count;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais transactions = array_get(&conn->transactions, &count);
c28749e97052f09388969427adf7df641cdcdc22kais for (i = 0; i < count; i++) {
c28749e97052f09388969427adf7df641cdcdc22kais if (transactions[i].id == id) {
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_assert(transactions[i].ctx == NULL);
efe05f9ecde56550699213909fd4152ef8ef6438krishna array_delete(&conn->transactions, i, 1);
c28749e97052f09388969427adf7df641cdcdc22kais return;
efe05f9ecde56550699213909fd4152ef8ef6438krishna }
efe05f9ecde56550699213909fd4152ef8ef6438krishna }
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_unreached();
efe05f9ecde56550699213909fd4152ef8ef6438krishna}
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishnastatic int cmd_begin(struct dict_connection_cmd *cmd, const char *line)
efe05f9ecde56550699213909fd4152ef8ef6438krishna{
efe05f9ecde56550699213909fd4152ef8ef6438krishna struct dict_connection_transaction *trans;
efe05f9ecde56550699213909fd4152ef8ef6438krishna unsigned int id;
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishna if (str_to_uint(line, &id) < 0) {
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_error("dict client: Invalid transaction ID %s", line);
efe05f9ecde56550699213909fd4152ef8ef6438krishna return -1;
efe05f9ecde56550699213909fd4152ef8ef6438krishna }
efe05f9ecde56550699213909fd4152ef8ef6438krishna if (dict_connection_transaction_lookup(cmd->conn, id) != NULL) {
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_error("dict client: Transaction ID %u already exists", id);
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
efe05f9ecde56550699213909fd4152ef8ef6438krishna }
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishna if (!array_is_created(&cmd->conn->transactions))
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_array_init(&cmd->conn->transactions, 4);
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais /* <id> */
efe05f9ecde56550699213909fd4152ef8ef6438krishna trans = array_append_space(&cmd->conn->transactions);
efe05f9ecde56550699213909fd4152ef8ef6438krishna trans->id = id;
efe05f9ecde56550699213909fd4152ef8ef6438krishna trans->conn = cmd->conn;
efe05f9ecde56550699213909fd4152ef8ef6438krishna trans->ctx = dict_transaction_begin(cmd->conn->dict);
efe05f9ecde56550699213909fd4152ef8ef6438krishna return 0;
efe05f9ecde56550699213909fd4152ef8ef6438krishna}
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishnastatic int
efe05f9ecde56550699213909fd4152ef8ef6438krishnadict_connection_transaction_lookup_parse(struct dict_connection *conn,
efe05f9ecde56550699213909fd4152ef8ef6438krishna const char *line,
efe05f9ecde56550699213909fd4152ef8ef6438krishna struct dict_connection_transaction **trans_r)
efe05f9ecde56550699213909fd4152ef8ef6438krishna{
efe05f9ecde56550699213909fd4152ef8ef6438krishna unsigned int id;
efe05f9ecde56550699213909fd4152ef8ef6438krishna
efe05f9ecde56550699213909fd4152ef8ef6438krishna if (str_to_uint(line, &id) < 0) {
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_error("dict client: Invalid transaction ID %s", line);
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
efe05f9ecde56550699213909fd4152ef8ef6438krishna *trans_r = dict_connection_transaction_lookup(conn, id);
efe05f9ecde56550699213909fd4152ef8ef6438krishna if (*trans_r == NULL) {
efe05f9ecde56550699213909fd4152ef8ef6438krishna i_error("dict client: Transaction ID %u doesn't exist", id);
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk return -1;
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk }
efe05f9ecde56550699213909fd4152ef8ef6438krishna return 0;
efe05f9ecde56550699213909fd4152ef8ef6438krishna}
c28749e97052f09388969427adf7df641cdcdc22kais
efe05f9ecde56550699213909fd4152ef8ef6438krishnastatic void
efe05f9ecde56550699213909fd4152ef8ef6438krishnacmd_commit_finish(struct dict_connection_cmd *cmd, int ret, bool async)
efe05f9ecde56550699213909fd4152ef8ef6438krishna{
efe05f9ecde56550699213909fd4152ef8ef6438krishna char chr;
c28749e97052f09388969427adf7df641cdcdc22kais
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk switch (ret) {
c28749e97052f09388969427adf7df641cdcdc22kais case 1:
c28749e97052f09388969427adf7df641cdcdc22kais chr = DICT_PROTOCOL_REPLY_OK;
c28749e97052f09388969427adf7df641cdcdc22kais break;
c28749e97052f09388969427adf7df641cdcdc22kais case 0:
c28749e97052f09388969427adf7df641cdcdc22kais chr = DICT_PROTOCOL_REPLY_NOTFOUND;
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk break;
c28749e97052f09388969427adf7df641cdcdc22kais default:
c28749e97052f09388969427adf7df641cdcdc22kais chr = DICT_PROTOCOL_REPLY_FAIL;
c28749e97052f09388969427adf7df641cdcdc22kais break;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais if (async) {
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup_printf("%c%c%u\n",
c28749e97052f09388969427adf7df641cdcdc22kais DICT_PROTOCOL_REPLY_ASYNC_COMMIT, chr, cmd->trans_id);
c28749e97052f09388969427adf7df641cdcdc22kais } else {
c28749e97052f09388969427adf7df641cdcdc22kais cmd->reply = i_strdup_printf("%c%u\n", chr, cmd->trans_id);
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_transaction_array_remove(cmd->conn, cmd->trans_id);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmds_flush(cmd->conn);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void cmd_commit_callback(int ret, void *context)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *cmd = context;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmd_commit_finish(cmd, ret, FALSE);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void cmd_commit_callback_async(int ret, void *context)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *cmd = context;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmd_commit_finish(cmd, ret, TRUE);
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int
c28749e97052f09388969427adf7df641cdcdc22kaiscmd_commit(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais cmd->trans_id = trans->id;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais dict_transaction_commit_async(&trans->ctx, cmd_commit_callback, cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return 1;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int
c28749e97052f09388969427adf7df641cdcdc22kaiscmd_commit_async(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais cmd->trans_id = trans->id;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais dict_transaction_commit_async(&trans->ctx, cmd_commit_callback_async, cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return 1;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_rollback(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais dict_transaction_rollback(&trans->ctx);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_transaction_array_remove(cmd->conn, trans->id);
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_set(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais const char *const *args;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais /* <id> <key> <value> */
c28749e97052f09388969427adf7df641cdcdc22kais args = t_strsplit_tabescaped(line);
c28749e97052f09388969427adf7df641cdcdc22kais if (str_array_length(args) != 3) {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("dict client: SET: broken input");
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais dict_set(trans->ctx, args[1], args[2]);
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk return 0;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_unset(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais const char *const *args;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais /* <id> <key> */
c28749e97052f09388969427adf7df641cdcdc22kais args = t_strsplit_tabescaped(line);
c28749e97052f09388969427adf7df641cdcdc22kais if (str_array_length(args) != 2) {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("dict client: UNSET: broken input");
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais dict_unset(trans->ctx, args[1]);
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic int cmd_atomic_inc(struct dict_connection_cmd *cmd, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_transaction *trans;
c28749e97052f09388969427adf7df641cdcdc22kais const char *const *args;
c28749e97052f09388969427adf7df641cdcdc22kais long long diff;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais /* <id> <key> <diff> */
c28749e97052f09388969427adf7df641cdcdc22kais args = t_strsplit_tabescaped(line);
c28749e97052f09388969427adf7df641cdcdc22kais if (str_array_length(args) != 3 ||
c28749e97052f09388969427adf7df641cdcdc22kais str_to_llong(args[2], &diff) < 0) {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("dict client: ATOMIC_INC: broken input");
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais dict_atomic_inc(trans->ctx, args[1], diff);
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic const struct dict_cmd_func cmds[] = {
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_LOOKUP, cmd_lookup },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_ITERATE, cmd_iterate },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_BEGIN, cmd_begin },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_COMMIT, cmd_commit },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_COMMIT_ASYNC, cmd_commit_async },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_ROLLBACK, cmd_rollback },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_SET, cmd_set },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_UNSET, cmd_unset },
c28749e97052f09388969427adf7df641cdcdc22kais { DICT_PROTOCOL_CMD_ATOMIC_INC, cmd_atomic_inc },
c28749e97052f09388969427adf7df641cdcdc22kais
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk { 0, NULL }
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk};
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vkstatic const struct dict_cmd_func *dict_command_find(enum dict_protocol_cmd cmd)
51dd2c77f06e5663c28bd4f7a760cae4cf159e79vk{
c28749e97052f09388969427adf7df641cdcdc22kais unsigned int i;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais for (i = 0; cmds[i].cmd != '\0'; i++) {
c28749e97052f09388969427adf7df641cdcdc22kais if (cmds[i].cmd == cmd)
c28749e97052f09388969427adf7df641cdcdc22kais return &cmds[i];
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais return NULL;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisint dict_command_input(struct dict_connection *conn, const char *line)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais const struct dict_cmd_func *cmd_func;
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *cmd;
c28749e97052f09388969427adf7df641cdcdc22kais int ret;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmd_func = dict_command_find((enum dict_protocol_cmd)*line);
c28749e97052f09388969427adf7df641cdcdc22kais if (cmd_func == NULL) {
c28749e97052f09388969427adf7df641cdcdc22kais i_error("dict client: Unknown command %c", *line);
c28749e97052f09388969427adf7df641cdcdc22kais return -1;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais cmd = i_new(struct dict_connection_cmd, 1);
c28749e97052f09388969427adf7df641cdcdc22kais cmd->conn = conn;
c28749e97052f09388969427adf7df641cdcdc22kais cmd->cmd = cmd_func;
c28749e97052f09388969427adf7df641cdcdc22kais array_append(&conn->cmds, &cmd, 1);
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_ref(conn);
c28749e97052f09388969427adf7df641cdcdc22kais if ((ret = cmd_func->func(cmd, line + 1)) <= 0) {
c28749e97052f09388969427adf7df641cdcdc22kais dict_connection_cmd_remove(cmd);
c28749e97052f09388969427adf7df641cdcdc22kais return ret;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais return 0;
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kaisstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd)
c28749e97052f09388969427adf7df641cdcdc22kais{
c28749e97052f09388969427adf7df641cdcdc22kais struct dict_connection_cmd *const *first_cmdp;
c28749e97052f09388969427adf7df641cdcdc22kais
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri first_cmdp = array_idx(&cmd->conn->cmds, 0);
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri if (*first_cmdp == cmd)
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri (void)cmd_iterate_flush(cmd);
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri}
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yendurivoid dict_connection_cmds_output_more(struct dict_connection *conn)
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri{
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri struct dict_connection_cmd *cmd, *const *first_cmdp;
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri
c28749e97052f09388969427adf7df641cdcdc22kais /* only iterators may be returning a lot of data */
c28749e97052f09388969427adf7df641cdcdc22kais while (array_count(&conn->cmds) > 0) {
c28749e97052f09388969427adf7df641cdcdc22kais first_cmdp = array_idx(&conn->cmds, 0);
c28749e97052f09388969427adf7df641cdcdc22kais cmd = *first_cmdp;
c28749e97052f09388969427adf7df641cdcdc22kais
c28749e97052f09388969427adf7df641cdcdc22kais if (cmd->iter == NULL)
c28749e97052f09388969427adf7df641cdcdc22kais break;
c28749e97052f09388969427adf7df641cdcdc22kais
51144063f3afc862c6cb3f54fd4341724f765075Krishna Yenduri if (cmd_iterate_flush(cmd) == 0) {
c28749e97052f09388969427adf7df641cdcdc22kais /* unfinished */
c28749e97052f09388969427adf7df641cdcdc22kais break;
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais /* cmd should be freed now */
c28749e97052f09388969427adf7df641cdcdc22kais }
c28749e97052f09388969427adf7df641cdcdc22kais}
c28749e97052f09388969427adf7df641cdcdc22kais