dict-commands.c revision e34d170f8f0e084bd94bfbc1a7085ece67e508df
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "lib.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "array.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "ostream.h"
c252d148fa8ab50aaaa8bbae7beb4d208025171dNikolai Kondrashov#include "str.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "dict-client.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "dict-settings.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "dict-connection.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "dict-commands.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include <stdlib.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#define DICT_OUTPUT_OPTIMAL_SIZE 1024
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozekstruct dict_client_cmd {
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose int cmd;
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher int (*func)(struct dict_connection *conn, const char *line);
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher};
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagherstatic int cmd_lookup(struct dict_connection *conn, const char *line)
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher{
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher const char *reply;
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov const char *value;
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher if (conn->iter_ctx != NULL) {
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher i_error("dict client: LOOKUP: Can't lookup while iterating");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* <key> */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = dict_lookup(conn->dict, pool_datastack_create(), line, &value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher reply = t_strdup_printf("%c%s\n",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DICT_PROTOCOL_REPLY_OK, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher o_stream_nsend_str(conn->output, reply);
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher reply = t_strdup_printf("%c\n", ret == 0 ?
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DICT_PROTOCOL_REPLY_NOTFOUND :
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DICT_PROTOCOL_REPLY_FAIL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher o_stream_nsend_str(conn->output, reply);
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose }
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose return 0;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose}
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bosestatic int cmd_iterate_flush(struct dict_connection *conn)
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose{
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke string_t *str;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke const char *key, *value;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose str = t_str_new(256);
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose o_stream_cork(conn->output);
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose while (dict_iterate(conn->iter_ctx, &key, &value)) {
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose str_truncate(str, 0);
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose str_printfa(str, "%c%s\t%s\n", DICT_PROTOCOL_REPLY_OK,
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose key, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher o_stream_nsend(conn->output, str_data(str), str_len(str));
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher if (o_stream_get_buffer_used_size(conn->output) >
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek DICT_OUTPUT_OPTIMAL_SIZE) {
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozek if (o_stream_flush(conn->output) <= 0) {
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek /* continue later */
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek o_stream_uncork(conn->output);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
d921c1eba437662437847279f251a0a5d8f70127Maxim /* flushed everything, continue */
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* finished iterating */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher o_stream_unset_flush_callback(conn->output);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_truncate(str, 0);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce if (dict_iterate_deinit(&conn->iter_ctx) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek str_append_c(str, '\n');
5377441d7a846461c2d9a7a870cea711360a529aNikolai Kondrashov o_stream_nsend(conn->output, str_data(str), str_len(str));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher o_stream_uncork(conn->output);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
32381402a4a9afc003782c9e2301fc59c9bda2a9Yassir Elley}
dbfc407eef1d9ba2469687c3ffbe7fd8bb111d94Jakub Hrozek
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagherstatic int cmd_iterate(struct dict_connection *conn, const char *line)
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher{
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek const char *const *args;
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek unsigned int flags;
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher
6dcbfe52d5e64205c0d922f3e89add066b42c496Jakub Hrozek if (conn->iter_ctx != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("dict client: ITERATE: Already iterating");
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return -1;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek args = t_strsplit_tab(line);
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek if (str_array_length(args) < 2 ||
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek str_to_uint(args[0], &flags) < 0) {
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek i_error("dict client: ITERATE: broken input");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* <flags> <path> */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->iter_ctx = dict_iterate_init_multiple(conn->dict, args+1, flags);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik o_stream_set_flush_callback(conn->output, cmd_iterate_flush, conn);
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik (void)cmd_iterate_flush(conn);
62bda5f75bda6b77aea30d708c74efaf725d9367Lukas Slebodnik return 0;
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek}
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct dict_connection_transaction *
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdict_connection_transaction_lookup(struct dict_connection *conn,
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik unsigned int id)
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection_transaction *transaction;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (!array_is_created(&conn->transactions))
558998ce664055a75595371118f818084d8f2b23Jan Cholasta return NULL;
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta array_foreach_modifiable(&conn->transactions, transaction) {
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (transaction->id == id)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta return transaction;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdict_connection_transaction_array_remove(struct dict_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection_transaction *trans)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny const struct dict_connection_transaction *transactions;
f1828234a850dd28465425248a83a993f262918fPavel Březina unsigned int i, count;
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina transactions = array_get(&conn->transactions, &count);
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina for (i = 0; i < count; i++) {
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina if (&transactions[i] == trans) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_delete(&conn->transactions, i, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int cmd_begin(struct dict_connection *conn, const char *line)
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek{
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek struct dict_connection_transaction *trans;
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek unsigned int id;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (str_to_uint(line, &id) < 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_error("dict client: Invalid transaction ID %s", line);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek return -1;
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek }
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek if (dict_connection_transaction_lookup(conn, id) != NULL) {
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta i_error("dict client: Transaction ID %u already exists", id);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta return -1;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta }
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek if (!array_is_created(&conn->transactions))
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek i_array_init(&conn->transactions, 4);
19d3aba12c70528708be9440aca66038a291f29eYassir Elley
19d3aba12c70528708be9440aca66038a291f29eYassir Elley /* <id> */
19d3aba12c70528708be9440aca66038a291f29eYassir Elley trans = array_append_space(&conn->transactions);
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek trans->id = id;
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek trans->conn = conn;
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek trans->ctx = dict_transaction_begin(conn->dict);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozekstatic int
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozekdict_connection_transaction_lookup_parse(struct dict_connection *conn,
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose const char *line,
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose struct dict_connection_transaction **trans_r)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek unsigned int id;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose if (str_to_uint(line, &id) < 0) {
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose i_error("dict client: Invalid transaction ID %s", line);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return -1;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *trans_r = dict_connection_transaction_lookup(conn, id);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*trans_r == NULL) {
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce i_error("dict client: Transaction ID %u doesn't exist", id);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int cmd_commit(struct dict_connection *conn, const char *line)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection_transaction *trans;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char chr;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (conn->iter_ctx != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("dict client: COMMIT: Can't commit while iterating");
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek return -1;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher }
fe60346714a73ac3987f786731389320633dd245Pavel Březina
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose if (dict_connection_transaction_lookup_parse(conn, line, &trans) < 0)
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose return -1;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ret = dict_transaction_commit(&trans->ctx);
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose switch (ret) {
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina case 1:
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher chr = DICT_PROTOCOL_REPLY_OK;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina break;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina case 0:
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina chr = DICT_PROTOCOL_REPLY_NOTFOUND;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina break;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina default:
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina chr = DICT_PROTOCOL_REPLY_FAIL;
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina break;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina }
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek o_stream_nsend_str(conn->output, t_strdup_printf("%c\n", chr));
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek dict_connection_transaction_array_remove(conn, trans);
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek return 0;
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek}
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozekstatic void cmd_commit_async_callback(int ret, void *context)
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection_transaction *trans = context;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek const char *reply;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek char chr;
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh switch (ret) {
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose case 1:
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha chr = DICT_PROTOCOL_REPLY_OK;
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha break;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek case 0:
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek chr = DICT_PROTOCOL_REPLY_NOTFOUND;
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose break;
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březina default:
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose chr = DICT_PROTOCOL_REPLY_FAIL;
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose break;
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek }
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek reply = t_strdup_printf("%c%c%u\n", DICT_PROTOCOL_REPLY_ASYNC_COMMIT,
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek chr, trans->id);
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek o_stream_nsend_str(trans->conn->output, reply);
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek dict_connection_transaction_array_remove(trans->conn, trans);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl}
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozekstatic int
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bosecmd_commit_async(struct dict_connection *conn, const char *line)
d36f4db9bb5efc63b94190cca25adb08ee56971cJakub Hrozek{
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek struct dict_connection_transaction *trans;
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose if (conn->iter_ctx != NULL) {
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina i_error("dict client: COMMIT: Can't commit while iterating");
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose return -1;
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose }
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina if (dict_connection_transaction_lookup_parse(conn, line, &trans) < 0)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return -1;
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek
ea422c7061072c125eb53b40d7f3ca444d886913Sumit Bose dict_transaction_commit_async(&trans->ctx, cmd_commit_async_callback,
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek trans);
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cech return 0;
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek}
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose
6cb5bad3c8e2f35ca9dce1800a506d626f90c079Lukas Slebodnikstatic int cmd_rollback(struct dict_connection *conn, const char *line)
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek{
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina struct dict_connection_transaction *trans;
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichl
62370340092503baeaf6587d7ffe4fe25bd9582dPavel Reichl if (dict_connection_transaction_lookup_parse(conn, line, &trans) < 0)
b407fe0474a674bb42f0f42ab47c7f530a07a367Pavel Březina return -1;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek dict_transaction_rollback(&trans->ctx);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek dict_connection_transaction_array_remove(conn, trans);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek return 0;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozekstatic int cmd_set(struct dict_connection *conn, const char *line)
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek{
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek struct dict_connection_transaction *trans;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek const char *const *args;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik /* <id> <key> <value> */
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik args = t_strsplit_tab(line);
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose if (str_array_length(args) != 3) {
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose i_error("dict client: SET: broken input");
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose return -1;
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose }
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik if (dict_connection_transaction_lookup_parse(conn, args[0], &trans) < 0)
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek return -1;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dict_set(trans->ctx, args[1], args[2]);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek}
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int cmd_unset(struct dict_connection *conn, const char *line)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek struct dict_connection_transaction *trans;
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek const char *const *args;
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek /* <id> <key> */
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher args = t_strsplit_tab(line);
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher if (str_array_length(args) != 2) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik i_error("dict client: UNSET: broken input");
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik return -1;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (dict_connection_transaction_lookup_parse(conn, args[0], &trans) < 0)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik return -1;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik dict_unset(trans->ctx, args[1]);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik return 0;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik}
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagherstatic int cmd_atomic_inc(struct dict_connection *conn, const char *line)
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher{
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik struct dict_connection_transaction *trans;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *const *args;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher long long diff;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov /* <id> <key> <diff> */
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov args = t_strsplit_tab(line);
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov if (str_array_length(args) != 3 ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_to_llong(args[2], &diff) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("dict client: ATOMIC_INC: broken input");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (dict_connection_transaction_lookup_parse(conn, args[0], &trans) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik dict_atomic_inc(trans->ctx, args[1], diff);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik return 0;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik}
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnikstatic struct dict_client_cmd cmds[] = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_LOOKUP, cmd_lookup },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_ITERATE, cmd_iterate },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_BEGIN, cmd_begin },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_COMMIT, cmd_commit },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_COMMIT_ASYNC, cmd_commit_async },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_ROLLBACK, cmd_rollback },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_SET, cmd_set },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { DICT_PROTOCOL_CMD_UNSET, cmd_unset },
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose { DICT_PROTOCOL_CMD_ATOMIC_INC, cmd_atomic_inc },
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose { 0, NULL }
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose};
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bosestatic struct dict_client_cmd *dict_command_find(char cmd)
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose{
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose unsigned int i;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose for (i = 0; cmds[i].cmd != '\0'; i++) {
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke if (cmds[i].cmd == cmd)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke return &cmds[i];
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke }
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke return NULL;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke}
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Boseint dict_command_input(struct dict_connection *conn, const char *line)
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose{
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose struct dict_client_cmd *cmd;
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose cmd = dict_command_find(*line);
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (cmd == NULL) {
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher i_error("dict client: Unknown command %c", *line);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return cmd->func(conn, line + 1);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik}
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik