]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict: Show command statistics in process title.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 25 May 2016 17:00:01 +0000 (20:00 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 25 May 2016 17:00:01 +0000 (20:00 +0300)
src/dict/Makefile.am
src/dict/dict-commands.c
src/dict/dict-commands.h
src/dict/dict-connection.c
src/dict/dict-connection.h
src/dict/dict-settings.c
src/dict/dict-settings.h
src/dict/main.c

index 93e7a42363a95c53de4f8b1f049dfd925d3e315e..4606de8902092bab8277834007c85071e05d533f 100644 (file)
@@ -33,4 +33,5 @@ dict_SOURCES = \
 noinst_HEADERS = \
        dict-connection.h \
        dict-commands.h \
-       dict-settings.h
+       dict-settings.h \
+       main.h
index b18fd48504b7c044fd2f6e643111f3e0d16de8be..8f13113e5289017bc697b211878a9fc8d6eb354c 100644 (file)
@@ -5,11 +5,13 @@
 #include "ostream.h"
 #include "str.h"
 #include "strescape.h"
+#include "timing.h"
+#include "time-util.h"
 #include "dict-client.h"
 #include "dict-settings.h"
 #include "dict-connection.h"
 #include "dict-commands.h"
-
+#include "main.h"
 
 #define DICT_OUTPUT_OPTIMAL_SIZE 1024
 
@@ -21,6 +23,7 @@ struct dict_cmd_func {
 struct dict_connection_cmd {
        const struct dict_cmd_func *cmd;
        struct dict_connection *conn;
+       struct timeval start_timeval;
        char *reply;
 
        struct dict_iterate_context *iter;
@@ -29,6 +32,8 @@ struct dict_connection_cmd {
        unsigned int trans_id;
 };
 
+struct dict_command_stats cmd_stats;
+
 static void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd);
 
 static void dict_connection_cmd_free(struct dict_connection_cmd *cmd)
@@ -82,11 +87,29 @@ static void dict_connection_cmds_flush(struct dict_connection *conn)
        dict_connection_unref_safe(conn);
 }
 
+static void
+cmd_stats_update(struct dict_connection_cmd *cmd, struct timing *timing)
+{
+       long long diff;
+
+       if (!dict_settings->verbose_proctitle)
+               return;
+
+       io_loop_time_refresh();
+       diff = timeval_diff_usecs(&ioloop_timeval, &cmd->start_timeval);
+       if (diff < 0)
+               diff = 0;
+       timing_add_usecs(timing, diff);
+       dict_proctitle_update_later();
+}
+
 static void
 cmd_lookup_callback(const struct dict_lookup_result *result, void *context)
 {
        struct dict_connection_cmd *cmd = context;
 
+       cmd_stats_update(cmd, cmd_stats.lookups);
+
        if (result->ret > 0) {
                cmd->reply = i_strdup_printf("%c%s\n",
                        DICT_PROTOCOL_REPLY_OK, str_tabescape(result->value));
@@ -149,6 +172,7 @@ static int cmd_iterate_flush(struct dict_connection_cmd *cmd)
        str_append_c(str, '\n');
        o_stream_uncork(cmd->conn->output);
 
+       cmd_stats_update(cmd, cmd_stats.iterations);
        cmd->reply = i_strdup(str_c(str));
        dict_connection_cmds_flush(cmd->conn);
        return 1;
@@ -267,6 +291,8 @@ cmd_commit_finish(struct dict_connection_cmd *cmd,
        string_t *str = t_str_new(64);
        char chr;
 
+       cmd_stats_update(cmd, cmd_stats.commits);
+
        switch (result->ret) {
        case 1:
                chr = DICT_PROTOCOL_REPLY_OK;
@@ -444,6 +470,7 @@ int dict_command_input(struct dict_connection *conn, const char *line)
        cmd = i_new(struct dict_connection_cmd, 1);
        cmd->conn = conn;
        cmd->cmd = cmd_func;
+       cmd->start_timeval = ioloop_timeval;
        array_append(&conn->cmds, &cmd, 1);
        dict_connection_ref(conn);
        if ((ret = cmd_func->func(cmd, line + 1)) <= 0) {
@@ -481,3 +508,17 @@ void dict_connection_cmds_output_more(struct dict_connection *conn)
                /* cmd should be freed now */
        }
 }
+
+void dict_commands_init(void)
+{
+       cmd_stats.lookups = timing_init();
+       cmd_stats.iterations = timing_init();
+       cmd_stats.commits = timing_init();
+}
+
+void dict_commands_deinit(void)
+{
+       timing_deinit(&cmd_stats.lookups);
+       timing_deinit(&cmd_stats.iterations);
+       timing_deinit(&cmd_stats.commits);
+}
index 03214c4e52081a3a0cf904cec22e64eddb4ce492..62200d0bbc456779bb0482756037a185d31f379f 100644 (file)
@@ -3,8 +3,19 @@
 
 struct dict_connection;
 
+struct dict_command_stats {
+       struct timing *lookups;
+       struct timing *iterations;
+       struct timing *commits;
+};
+
+extern struct dict_command_stats cmd_stats;
+
 int dict_command_input(struct dict_connection *conn, const char *line);
 
 void dict_connection_cmds_output_more(struct dict_connection *conn);
 
+void dict_commands_init(void);
+void dict_commands_deinit(void);
+
 #endif
index 0c2677b1a34b0dd7427227b8ee98b5f585b0b788..7cf9b79bca04a13ae82f7e3d412ba78d95f438a6 100644 (file)
@@ -17,6 +17,7 @@
 #define DICT_CONN_MAX_PENDING_COMMANDS 5
 
 static struct dict_connection *dict_connections;
+static unsigned int dict_connections_count = 0;
 
 static int dict_connection_parse_handshake(struct dict_connection *conn,
                                           const char *line)
@@ -199,6 +200,8 @@ struct dict_connection *dict_connection_create(int fd)
        o_stream_set_flush_callback(conn->output, dict_connection_output, conn);
        conn->io = io_add(fd, IO_READ, dict_connection_input, conn);
        i_array_init(&conn->cmds, DICT_CONN_MAX_PENDING_COMMANDS);
+
+       dict_connections_count++;
        DLLIST_PREPEND(&dict_connections, conn);
        return conn;
 }
@@ -273,6 +276,9 @@ void dict_connection_destroy(struct dict_connection *conn)
        i_assert(!conn->destroyed);
        i_assert(conn->to_unref == NULL);
 
+       i_assert(dict_connections_count > 0);
+       dict_connections_count--;
+
        conn->destroyed = TRUE;
        DLLIST_REMOVE(&dict_connections, conn);
 
@@ -297,6 +303,11 @@ void dict_connection_destroy(struct dict_connection *conn)
        dict_connection_unref(conn);
 }
 
+unsigned int dict_connections_current_count(void)
+{
+       return dict_connections_count;
+}
+
 void dict_connections_destroy_all(void)
 {
        while (dict_connections != NULL)
index 87187993128f6c22472646170089ff527e01ccd1..2f9149c0f05b76b8a5cb6b7f2eba3d2ff364ba3c 100644 (file)
@@ -43,6 +43,7 @@ void dict_connection_unref_safe(struct dict_connection *conn);
 
 void dict_connection_continue_input(struct dict_connection *conn);
 
+unsigned int dict_connections_current_count(void);
 void dict_connections_destroy_all(void);
 
 #endif
index 53a27e3c1798572419be3c62959215029c68f353..6b36cac62bbd1533bc5cd880bffa57063ae94c12 100644 (file)
@@ -86,6 +86,8 @@ struct service_settings dict_async_service_settings = {
 
 static const struct setting_define dict_setting_defines[] = {
        DEF(SET_STR, base_dir),
+       DEF(SET_BOOL, verbose_proctitle),
+
        DEF(SET_STR, dict_db_config),
        { SET_STRLIST, "dict", offsetof(struct dict_server_settings, dicts), NULL },
 
@@ -94,6 +96,8 @@ static const struct setting_define dict_setting_defines[] = {
 
 const struct dict_server_settings dict_default_settings = {
        .base_dir = PKG_RUNDIR,
+       .verbose_proctitle = FALSE,
+
        .dict_db_config = "",
        .dicts = ARRAY_INIT
 };
index 0068ef04a46f9d4ea300e25cdb7c207044a6ee36..3c37589e9bedd6eb704f660003e5d8c731824339 100644 (file)
@@ -3,6 +3,8 @@
 
 struct dict_server_settings {
        const char *base_dir;
+       bool verbose_proctitle;
+
        const char *dict_db_config;
        ARRAY(const char *) dicts;
 };
index e6c945eb918d63d9a4b23daa2e54fe1d454b016d..f1d89fe27f9924bcd61b00b0666212e5e921fda7 100644 (file)
@@ -2,8 +2,12 @@
 
 #include "lib.h"
 #include "restrict-access.h"
+#include "ioloop.h"
 #include "randgen.h"
+#include "str.h"
 #include "hostpid.h"
+#include "timing.h"
+#include "process-title.h"
 #include "env-util.h"
 #include "module-dir.h"
 #include "master-service.h"
 #include "sql-api.h"
 #include "dict.h"
 #include "dict-client.h"
+#include "dict-commands.h"
 #include "dict-connection.h"
 #include "dict-settings.h"
+#include "main.h"
 
 static struct module *modules;
+static struct timeout *to_proctitle;
+static bool proctitle_updated;
+
+static void
+add_timing_string(string_t *str, struct timing *timing, const char *name)
+{
+       str_printfa(str, ", %u %s:%llu/%llu/%llu/%llu",
+                   timing_get_count(timing), name,
+                   (unsigned long long)timing_get_min(timing)/1000,
+                   (unsigned long long)timing_get_avg(timing)/1000,
+                   (unsigned long long)timing_get_95th(timing)/1000,
+                   (unsigned long long)timing_get_max(timing)/1000);
+       timing_reset(timing);
+}
+
+static void dict_proctitle_update(void *context ATTR_UNUSED)
+{
+       string_t *str = t_str_new(128);
+
+       if (!proctitle_updated)
+               timeout_remove(&to_proctitle);
+
+       str_printfa(str, "[%u clients", dict_connections_current_count());
+
+       add_timing_string(str, cmd_stats.lookups, "lookups");
+       add_timing_string(str, cmd_stats.iterations, "iters");
+       add_timing_string(str, cmd_stats.commits, "commits");
+       str_append_c(str, ']');
+
+       process_title_set(str_c(str));
+       proctitle_updated = FALSE;
+}
+
+void dict_proctitle_update_later(void)
+{
+       if (!dict_settings->verbose_proctitle)
+               return;
+
+       if (to_proctitle == NULL)
+               to_proctitle = timeout_add(1000, dict_proctitle_update, NULL);
+       proctitle_updated = TRUE;
+}
 
 static void dict_die(void)
 {
@@ -68,12 +116,17 @@ static void main_init(void)
        /* Register only after loading modules. They may contain SQL drivers,
           which we'll need to register. */
        dict_drivers_register_all();
+       dict_commands_init();
 }
 
 static void main_deinit(void)
 {
+       if (to_proctitle != NULL)
+               timeout_remove(&to_proctitle);
+
        dict_connections_destroy_all();
        dict_drivers_unregister_all();
+       dict_commands_deinit();
 
        module_dir_unload(&modules);
 
@@ -83,8 +136,7 @@ static void main_deinit(void)
 
 int main(int argc, char *argv[])
 {
-       const enum master_service_flags service_flags =
-               MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
+       const enum master_service_flags service_flags = 0;
        const struct setting_parser_info *set_roots[] = {
                &dict_setting_parser_info,
                NULL