From: Timo Sirainen Date: Mon, 14 Nov 2016 22:32:05 +0000 (+0100) Subject: lib-settings: Avoid duplicating settings' values when not needed X-Git-Tag: 2.2.27~114 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=758c7196531d8e8fc92ab593a66fcef0bd06f1fd;p=thirdparty%2Fdovecot%2Fcore.git lib-settings: Avoid duplicating settings' values when not needed --- diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c index ed5c061079..0dc7d745bc 100644 --- a/src/lib-settings/settings-parser.c +++ b/src/lib-settings/settings-parser.c @@ -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); diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h index b68195a65f..25e6d6917c 100644 --- a/src/lib-settings/settings-parser.h +++ b/src/lib-settings/settings-parser.h @@ -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,