]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict: Support accessing non-legacy dicts
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 21 Mar 2024 22:25:36 +0000 (00:25 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:13 +0000 (12:34 +0200)
The dicts can be configured inside dict_server { .. } filter, e.g.:

dict_server {
  dict cassandra {
    ..
  }
  dict cassandra2 {
    driver = cassandra
    ..
  }
}

src/dict/dict-connection.c
src/dict/dict-expire.c
src/dict/dict-init-cache.c
src/dict/dict-init-cache.h
src/dict/dict-settings.c
src/dict/dict-settings.h
src/dict/main.c

index 95208a09cca7f58a513f2ecb6fd97b03103063c2..37b2ff69c345e6de4998188ac7a6c58e4fea070c 100644 (file)
@@ -7,6 +7,7 @@
 #include "ostream.h"
 #include "llist.h"
 #include "strescape.h"
+#include "settings.h"
 #include "master-service.h"
 #include "dict-client.h"
 #include "dict-settings.h"
@@ -22,10 +23,6 @@ static int dict_connection_dict_init(struct dict_connection *conn);
 static void dict_connection_destroy(struct connection *_conn);
 struct connection_list *dict_connections = NULL;
 
-static  struct event_category dict_server_event_category = {
-       .name = "dict-server",
-};
-
 static int dict_connection_handshake_args(struct connection *_conn,
                                          const char *const *args)
 {
@@ -66,28 +63,23 @@ static int dict_connection_handshake_line(struct connection *conn,
        return dict_connection_handshake_args(conn, args);
 }
 
-static int dict_connection_dict_init(struct dict_connection *conn)
+static int dict_connection_dict_init_legacy(struct dict_connection *conn)
 {
        struct dict_legacy_settings dict_set;
        const char *const *strlist;
        unsigned int i, count;
        const char *uri, *error;
 
-       if (!array_is_created(&server_settings->legacy_dicts)) {
-               e_error(conn->conn.event, "No dictionaries configured");
-               return -1;
-       }
+       if (!array_is_created(&server_settings->legacy_dicts))
+               return 0;
        strlist = array_get(&server_settings->legacy_dicts, &count);
        for (i = 0; i < count; i += 2) {
                if (strcmp(strlist[i], conn->name) == 0)
                        break;
        }
 
-       if (i == count) {
-               e_error(conn->conn.event, "Unconfigured dictionary name '%s'",
-                       conn->name);
-               return -1;
-       }
+       if (i == count)
+               return 0;
        event_set_append_log_prefix(conn->conn.event,
                                    t_strdup_printf("%s: ", conn->name));
        event_add_str(conn->conn.event, "dict_name", conn->name);
@@ -103,6 +95,57 @@ static int dict_connection_dict_init(struct dict_connection *conn)
                        conn->name, error);
                return -1;
        }
+       return 1;
+}
+
+static int dict_connection_dict_init_name(struct dict_connection *conn)
+{
+       struct event *event;
+       const char *error;
+
+       event_set_append_log_prefix(conn->conn.event,
+                                   t_strdup_printf("%s: ", conn->name));
+
+       /* The dict is persistently cached, so don't use connection's event. */
+       event = event_create(master_service_get_event(master_service));
+       event_set_append_log_prefix(event, t_strdup_printf("%s: ", conn->name));
+       event_add_str(event, "dict_name", conn->name);
+
+       if (dict_init_cache_get(event, conn->name, &conn->dict, &error) < 0) {
+               e_error(conn->conn.event, "Failed to initialize dictionary '%s': %s",
+                       conn->name, error);
+               event_unref(&event);
+               return -1;
+       }
+       event_unref(&event);
+       return 0;
+}
+
+static int dict_connection_dict_init(struct dict_connection *conn)
+{
+       int ret = 0;
+
+       if (array_is_created(&dict_settings->dicts)) {
+               const char *dict_name;
+               array_foreach_elem(&dict_settings->dicts, dict_name) {
+                       if (strcmp(conn->name, dict_name) == 0) {
+                               if (dict_connection_dict_init_name(conn) < 0)
+                                       return -1;
+                               ret = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (ret == 0) {
+               if ((ret = dict_connection_dict_init_legacy(conn)) < 0)
+                       return -1;
+       }
+       if (ret == 0) {
+               e_error(conn->conn.event, "Unconfigured dictionary name '%s'",
+                       conn->name);
+               return -1;
+       }
        return 0;
 }
 
index 931718484a49585f8d94669f01c03bc8de0bc9d0..aaa313854f6a37f4fbe4fad40ab63cdcaa371d74 100644 (file)
@@ -63,7 +63,7 @@ static void client_connected(struct master_service_connection *conn ATTR_UNUSED)
        dict_expire_run();
 }
 
-static void dict_expire_init(void)
+static void dict_expire_init_legacy(void)
 {
        struct dict_legacy_settings dict_set = {
                .base_dir = server_settings->base_dir,
@@ -72,7 +72,8 @@ static void dict_expire_init(void)
        const char *const *strlist, *error;
        unsigned int i, count;
 
-       i_array_init(&expire_dicts, 16);
+       if (!array_is_created(&server_settings->legacy_dicts))
+               return;
        strlist = array_get(&server_settings->legacy_dicts, &count);
        for (i = 0; i < count; i += 2) {
                const char *name = strlist[i];
@@ -90,6 +91,30 @@ static void dict_expire_init(void)
        }
 }
 
+static void dict_expire_init(struct event *event)
+{
+       i_array_init(&expire_dicts, 16);
+       dict_expire_init_legacy();
+
+       if (!array_is_created(&dict_settings->dicts))
+               return;
+
+       struct dict *dict;
+       const char *dict_name, *error;
+       array_foreach_elem(&dict_settings->dicts, dict_name) {
+               if (dict_init_filter_auto(event, dict_name, &dict, &error) < 0) {
+                       i_error("Failed to initialize dictionary '%s': %s - skipping",
+                               dict_name, error);
+               } else {
+                       struct expire_dict *expire_dict =
+                               array_append_space(&expire_dicts);
+                       expire_dict->name = dict_name;
+                       expire_dict->dict = dict;
+               }
+       }
+
+}
+
 static void main_preinit(void)
 {
        /* Load built-in SQL drivers (if any) */
@@ -105,10 +130,14 @@ static void main_preinit(void)
 static void main_init(void)
 {
        struct module_dir_load_settings mod_set;
+       struct event *event = master_service_get_event(master_service);
 
+       event_add_category(event, &dict_server_event_category);
+       event_set_ptr(event, SETTINGS_EVENT_FILTER_NAME, "dict_server");
        server_settings =
-               settings_get_or_fatal(master_service_get_event(master_service),
-                                     &dict_server_setting_parser_info);
+               settings_get_or_fatal(event, &dict_server_setting_parser_info);
+       dict_settings =
+               settings_get_or_fatal(event, &dict_setting_parser_info);
 
        i_zero(&mod_set);
        mod_set.abi_version = DOVECOT_ABI_VERSION;
@@ -121,7 +150,7 @@ static void main_init(void)
           which we'll need to register. */
        dict_drivers_register_all();
 
-       dict_expire_init();
+       dict_expire_init(event);
        to_expire = timeout_add(DICT_EXPIRE_RUN_INTERVAL_MSECS,
                                dict_expire_timeout, NULL);
 }
@@ -140,6 +169,7 @@ static void main_deinit(void)
        sql_drivers_deinit();
        timeout_remove(&to_expire);
        settings_free(server_settings);
+       settings_free(dict_settings);
 }
 
 int main(int argc, char *argv[])
index 779b6b3a5a1cd076ad7ec8ee06291c063121370a..146ec26e8af3d435111ea8b72c9a2a8587aa3bef 100644 (file)
@@ -75,6 +75,25 @@ static struct dict_init_cache_list *dict_init_cache_find(const char *dict_name)
        return match;
 }
 
+int dict_init_cache_get(struct event *event, const char *dict_name,
+                       struct dict **dict_r, const char **error_r)
+{
+       struct dict_init_cache_list *match;
+       int ret = 0;
+
+       match = dict_init_cache_find(dict_name);
+       if (match == NULL) {
+               if (dict_init_filter_auto(event, dict_name, dict_r, error_r) <= 0)
+                       return -1;
+               match = dict_init_cache_add(dict_name, *dict_r);
+       } else {
+               match->refcount++;
+               *dict_r = match->dict;
+       }
+       i_assert(match->dict != NULL);
+       return ret;
+}
+
 int dict_init_cache_get_legacy(const char *dict_name, const char *uri,
                               const struct dict_legacy_settings *set,
                               struct dict **dict_r, const char **error_r)
index e66f5d331d6c10e7a87ca0a55763f7e672ab2fb6..afd438508428abf39a1e4de9df811a3ccc49b0d1 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef DICT_INIT_CACHE_H
 #define DICT_INIT_CACHE_H
 
+int dict_init_cache_get(struct event *event, const char *dict_name,
+                       struct dict **dict_r, const char **error_r);
 int dict_init_cache_get_legacy(const char *dict_name, const char *uri,
                               const struct dict_legacy_settings *set,
                               struct dict **dict_r, const char **error_r);
index f551cb11ac367aca8556673fc599214343c8dad0..0224fc083ddf9a456938f87d9122e0cd1dc873a9 100644 (file)
@@ -90,6 +90,8 @@ struct service_settings dict_expire_service_settings = {
        SETTING_DEFINE_STRUCT_##type(#name, name, struct dict_server_settings)
 
 static const struct setting_define dict_setting_defines[] = {
+       { .type = SET_FILTER_NAME, .key = "dict_server" },
+
        DEF(STR_HIDDEN, base_dir),
        DEF(BOOL, verbose_proctitle),
        { .type = SET_STRLIST, .key = "dict_legacy",
@@ -115,3 +117,8 @@ const struct setting_parser_info dict_server_setting_parser_info = {
 };
 
 const struct dict_server_settings *server_settings;
+const struct dict_settings *dict_settings;
+
+struct event_category dict_server_event_category = {
+       .name = "dict-server",
+};
index 8518f0c94e044e947790a26ec2917ab40a604bc7..9930cbe275d4c69528d7ecf2006e89256278a1f7 100644 (file)
@@ -10,5 +10,8 @@ struct dict_server_settings {
 
 extern const struct setting_parser_info dict_server_setting_parser_info;
 extern const struct dict_server_settings *server_settings;
+extern const struct dict_settings *dict_settings;
+
+extern struct event_category dict_server_event_category;
 
 #endif
index 9d8d9920922feeb7b3fdb5bf8af29e1a8ee0aac1..9b3637c9612a1b7500d3f2b8493d07e043d3b993 100644 (file)
@@ -100,11 +100,15 @@ static void main_preinit(void)
 
 static void main_init(void)
 {
+       struct event *event = master_service_get_event(master_service);
        struct module_dir_load_settings mod_set;
 
+       event_add_category(event, &dict_server_event_category);
+       event_set_ptr(event, SETTINGS_EVENT_FILTER_NAME, "dict_server");
        server_settings =
-               settings_get_or_fatal(master_service_get_event(master_service),
-                                     &dict_server_setting_parser_info);
+               settings_get_or_fatal(event, &dict_server_setting_parser_info);
+       dict_settings =
+               settings_get_or_fatal(event, &dict_setting_parser_info);
 
        i_zero(&mod_set);
        mod_set.abi_version = DOVECOT_ABI_VERSION;
@@ -138,6 +142,7 @@ static void main_deinit(void)
 
        sql_drivers_deinit();
        timeout_remove(&to_proctitle);
+       settings_free(dict_settings);
        settings_free(server_settings);
 }