]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-settings: Lookup override setting keys only once
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sun, 28 May 2023 20:09:55 +0000 (23:09 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:08 +0000 (12:34 +0200)
After the key is found, remember its index so it can be directly used.

src/lib-settings/settings-parser.c
src/lib-settings/settings-parser.h
src/lib-settings/settings.c

index e1a14f6d0d232b97baa6df84ad71259d59eb9ca7..0a820fa9a4bff71bfcc4a3e8cf886d1627b373cf 100644 (file)
@@ -156,6 +156,30 @@ setting_parser_info_get_define_count(const struct setting_parser_info *info)
        return count;
 }
 
+bool setting_parser_info_find_key(const struct setting_parser_info *info,
+                                 const char *key, unsigned int *idx_r)
+{
+       const char *suffix;
+
+       for (unsigned int i = 0; info->defines[i].key != NULL; i++) {
+               if (!str_begins(key, info->defines[i].key, &suffix))
+                       ; /* mismatch */
+               else if (suffix[0] == '\0') {
+                       /* full setting */
+                       while (i > 0 && info->defines[i].type == SET_ALIAS)
+                               i--;
+                       *idx_r = i;
+                       return TRUE;
+               } else if (suffix[0] == '/' &&
+                          info->defines[i].type == SET_STRLIST) {
+                       /* strlist key */
+                       *idx_r = i;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
 void *settings_parser_get_set(const struct setting_parser_context *ctx)
 {
        return ctx->set_struct;
index 2681ea2a6435aa86deb691aa71a8e7bf4b6c7c13..055f9f125943abb5a6f70d24b5154bb9f099c52f 100644 (file)
@@ -144,6 +144,11 @@ void settings_parser_unref(struct setting_parser_context **ctx);
 /* Returns number of defines in info->defines */
 unsigned int
 setting_parser_info_get_define_count(const struct setting_parser_info *info);
+/* Find a specific key from info and return its index number in the defines
+   array. "strlist/key" will return the strlist's define. If the key is an
+   alias, the primary key's index is returned. */
+bool setting_parser_info_find_key(const struct setting_parser_info *info,
+                                 const char *key, unsigned int *idx_r);
 
 /* Returns the current settings. */
 void *settings_parser_get_set(const struct setting_parser_context *ctx);
index 4f04a303c2cc46d06e578655d43a2b2927621a96..e8ee49f402fe6e3438c4ec0b1abc97385ea5969d 100644 (file)
@@ -876,14 +876,14 @@ static int settings_override_cmp(const struct settings_override *set1,
 }
 
 static int
-settings_override_get_value(struct setting_parser_context *parser,
+settings_override_get_value(struct settings_apply_ctx *ctx,
                            const struct settings_override *set,
-                           const char **_key, const char **value_r,
-                           const char **error_r)
+                           const char **_key, unsigned int *key_idx_r,
+                           const char **value_r, const char **error_r)
 {
        const char *key = *_key;
-       enum setting_type value_type;
-       const void *old_value = NULL;
+       unsigned int key_idx = UINT_MAX;
+
        if (set->last_filter_value != NULL) {
                i_assert(set->last_filter_key != NULL);
                /* Try filter/name/key -> filter_key. Do this before the
@@ -894,14 +894,16 @@ settings_override_get_value(struct setting_parser_context *parser,
                        key_prefix = SETTINGS_EVENT_MAILBOX_NAME_WITH_PREFIX;
                const char *prefixed_key =
                        t_strdup_printf("%s_%s", key_prefix, key);
-               old_value = settings_parse_get_value(parser, &prefixed_key, &value_type);
-               if (old_value != NULL)
+               if (setting_parser_info_find_key(ctx->info, prefixed_key,
+                                                &key_idx))
                        key = prefixed_key;
        }
-       if (old_value == NULL)
-               old_value = settings_parse_get_value(parser, &key, &value_type);
-       if (old_value == NULL && !str_begins_with(key, "plugin/") &&
-           set->type == SETTINGS_OVERRIDE_TYPE_USERDB) {
+       if (key_idx == UINT_MAX)
+               (void)setting_parser_info_find_key(ctx->info, key, &key_idx);
+
+       if (key_idx == UINT_MAX && strchr(key, '/') == NULL &&
+           set->type == SETTINGS_OVERRIDE_TYPE_USERDB &&
+           setting_parser_info_find_key(ctx->info, "plugin", &key_idx)) {
                /* FIXME: Setting is unknown in this parser. Since the parser
                   doesn't know all settings, we can't be sure if it's because
                   it should simply be ignored or because it's a plugin setting.
@@ -909,23 +911,25 @@ settings_override_get_value(struct setting_parser_context *parser,
                   removed eventually once all plugin settings have been
                   converted away. */
                key = t_strconcat("plugin/", key, NULL);
-               old_value = settings_parse_get_value(parser, &key, &value_type);
        }
-       if (old_value == NULL)
+       if (key_idx == UINT_MAX)
                return 0;
        if (!set->append) {
                *_key = key;
+               *key_idx_r = key_idx;
                *value_r = set->value;
                return 1;
        }
 
-       if (value_type != SET_STR) {
+       if (ctx->info->defines[key_idx].type != SET_STR) {
                *error_r = t_strdup_printf(
                        "%s setting is not a string - can't use '+'", key);
                return -1;
        }
-       const char *const *strp = old_value;
+       const char *const *strp =
+               PTR_OFFSET(ctx->set_struct, ctx->info->defines[key_idx].offset);
        *_key = key;
+       *key_idx_r = key_idx;
        *value_r = t_strconcat(*strp, set->value, NULL);
        return 1;
 }
@@ -951,6 +955,7 @@ settings_instance_override(struct settings_apply_ctx *ctx,
        const struct settings_override *set;
        array_foreach(&overrides, set) {
                const char *key = set->key, *value;
+               unsigned int key_idx;
 
                if (set->filter != NULL &&
                    !event_filter_match(set->filter, ctx->event, &failure_ctx))
@@ -961,8 +966,8 @@ settings_instance_override(struct settings_apply_ctx *ctx,
                    null_strcmp(ctx->filter_value, set->last_filter_value) == 0)
                        seen_filter = TRUE;
 
-               int ret = settings_override_get_value(ctx->parser, set,
-                                                     &key, &value, error_r);
+               int ret = settings_override_get_value(ctx, set, &key,
+                                                     &key_idx, &value, error_r);
                if (ret < 0)
                        return -1;
                if (ret == 0) {
@@ -986,7 +991,8 @@ settings_instance_override(struct settings_apply_ctx *ctx,
                        else if (ctx->instance->pool != NULL)
                                pool_add_external_ref(&ctx->mpool->pool, ctx->instance->pool);
                }
-               if (settings_parse_keyvalue_nodup(ctx->parser, key, value) < 0) {
+               if (settings_parse_keyidx_value_nodup(ctx->parser, key_idx, key,
+                                                     value) < 0) {
                        *error_r = t_strdup_printf(
                                "Failed to override configuration from %s: "
                                "Invalid %s=%s: %s",