noinst_HEADERS = \
dict-connection.h \
dict-commands.h \
- dict-settings.h
+ dict-settings.h \
+ main.h
#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
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;
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)
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));
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;
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;
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) {
/* 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);
+}
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
#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)
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;
}
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);
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)
void dict_connection_continue_input(struct dict_connection *conn);
+unsigned int dict_connections_current_count(void);
void dict_connections_destroy_all(void);
#endif
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 },
const struct dict_server_settings dict_default_settings = {
.base_dir = PKG_RUNDIR,
+ .verbose_proctitle = FALSE,
+
.dict_db_config = "",
.dicts = ARRAY_INIT
};
struct dict_server_settings {
const char *base_dir;
+ bool verbose_proctitle;
+
const char *dict_db_config;
ARRAY(const char *) dicts;
};
#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)
{
/* 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);
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