]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-settings: Avoid duplicating settings' values when not needed
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 14 Nov 2016 22:32:05 +0000 (23:32 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 18 Nov 2016 11:55:49 +0000 (13:55 +0200)
src/lib-settings/settings-parser.c
src/lib-settings/settings-parser.h

index ed5c061079983fa923952c5ee61613d485406b6c..0dc7d745bc91a86671009266ee65070b56acaaa0 100644 (file)
@@ -1402,7 +1402,8 @@ static void settings_set_parent(const struct setting_parser_info *info,
 }
 
 static bool
-setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool)
+setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool,
+            bool keep_values)
 {
        switch (type) {
        case SET_BOOL: {
@@ -1441,7 +1442,10 @@ setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool)
                const char *const *src_str = src;
                const char **dest_str = dest;
 
-               *dest_str = p_strdup(pool, *src_str);
+               if (keep_values)
+                       *dest_str = *src_str;
+               else
+                       *dest_str = p_strdup(pool, *src_str);
                break;
        }
        case SET_DEFLIST:
@@ -1472,9 +1476,9 @@ setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool)
                                if (j < dest_count)
                                        continue;
                        }
-                       dup = p_strdup(pool, strings[i]);
+                       dup = keep_values ? strings[i] : p_strdup(pool, strings[i]);
                        array_append(dest_arr, &dup, 1);
-                       dup = p_strdup(pool, strings[i+1]);
+                       dup = keep_values ? strings[i+1] : p_strdup(pool, strings[i+1]);
                        array_append(dest_arr, &dup, 1);
                }
                break;
@@ -1485,8 +1489,8 @@ setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool)
        return TRUE;
 }
 
-void *settings_dup(const struct setting_parser_info *info,
-                  const void *set, pool_t pool)
+static void *settings_dup_full(const struct setting_parser_info *info,
+                              const void *set, pool_t pool, bool keep_values)
 {
        const struct setting_define *def;
        const void *src;
@@ -1503,7 +1507,7 @@ void *settings_dup(const struct setting_parser_info *info,
                src = CONST_PTR_OFFSET(set, def->offset);
                dest = PTR_OFFSET(dest_set, def->offset);
 
-               if (!setting_copy(def->type, src, dest, pool)) {
+               if (!setting_copy(def->type, src, dest, pool, keep_values)) {
                        const ARRAY_TYPE(void_array) *src_arr = src;
                        ARRAY_TYPE(void_array) *dest_arr = dest;
                        void *child_set;
@@ -1514,8 +1518,9 @@ void *settings_dup(const struct setting_parser_info *info,
                        children = array_get(src_arr, &count);
                        p_array_init(dest_arr, pool, count);
                        for (i = 0; i < count; i++) {
-                               child_set = settings_dup(def->list_info,
-                                                        children[i], pool);
+                               child_set = settings_dup_full(def->list_info,
+                                                             children[i], pool,
+                                                             keep_values);
                                array_append(dest_arr, &child_set, 1);
                                settings_set_parent(def->list_info, child_set,
                                                    dest_set);
@@ -1525,6 +1530,18 @@ void *settings_dup(const struct setting_parser_info *info,
        return dest_set;
 }
 
+void *settings_dup(const struct setting_parser_info *info,
+                  const void *set, pool_t pool)
+{
+       return settings_dup_full(info, set, pool, FALSE);
+}
+
+void *settings_dup_with_pointers(const struct setting_parser_info *info,
+                                const void *set, pool_t pool)
+{
+       return settings_dup_full(info, set, pool, TRUE);
+}
+
 static void *
 settings_changes_dup(const struct setting_parser_info *info,
                     const void *change_set, pool_t pool)
@@ -1806,6 +1823,11 @@ settings_parser_dup(const struct setting_parser_context *old_ctx,
        char *key;
        unsigned int i;
        pool_t parser_pool;
+       bool keep_values;
+
+       /* if source and destination pools are the same, there's no need to
+          duplicate values */
+       keep_values = new_pool == old_ctx->set_pool;
 
        pool_ref(new_pool);
        parser_pool = pool_alloconly_create(MEMPOOL_GROWING"dup settings parser",
@@ -1830,9 +1852,9 @@ settings_parser_dup(const struct setting_parser_context *old_ctx,
 
                new_ctx->roots[i].info = old_ctx->roots[i].info;
                new_ctx->roots[i].set_struct =
-                       settings_dup(old_ctx->roots[i].info,
-                                    old_ctx->roots[i].set_struct,
-                                    new_ctx->set_pool);
+                       settings_dup_full(old_ctx->roots[i].info,
+                                         old_ctx->roots[i].set_struct,
+                                         new_ctx->set_pool, keep_values);
                new_ctx->roots[i].change_struct =
                        settings_changes_dup(old_ctx->roots[i].info,
                                             old_ctx->roots[i].change_struct,
@@ -2041,7 +2063,7 @@ settings_apply(struct setting_link *dest_link,
                src = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
                dest = PTR_OFFSET(dest_link->set_struct, def->offset);
 
-               if (setting_copy(def->type, src, dest, pool)) {
+               if (setting_copy(def->type, src, dest, pool, FALSE)) {
                        /* non-list */
                } else if (def->type == SET_DEFLIST) {
                        settings_copy_deflist(def, src_link, dest_link, pool);
index b68195a65f41b73111daf3c670bbac7034a7c3bb..25e6d6917c9430900430e4cacab9601836c7b9a7 100644 (file)
@@ -197,6 +197,10 @@ bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
 /* Duplicate the entire settings structure. */
 void *settings_dup(const struct setting_parser_info *info,
                   const void *set, pool_t pool);
+/* Same as settings_dup(), but assume that the old pointers can still be safely
+   used. This saves memory since strings don't have to be duplicated. */
+void *settings_dup_with_pointers(const struct setting_parser_info *info,
+                                const void *set, pool_t pool);
 /* Duplicate the entire setting parser. */
 struct setting_parser_context *
 settings_parser_dup(const struct setting_parser_context *old_ctx,