]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-master: Add mempool for master settings
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 4 Jan 2023 21:20:47 +0000 (23:20 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 20 Nov 2023 12:11:40 +0000 (14:11 +0200)
This will simplify tracking memory usage for settings structs.

src/lib-master/master-service-settings.c
src/lib-master/master-service.c

index dc1f1d6137ff300376b42a5d4ea208b8cd356cf2..742dfff64fecaf65e084c989205eca683f7108b1 100644 (file)
@@ -35,6 +35,8 @@ struct master_settings_mmap {
        size_t mmap_size;
 };
 
+static pool_t master_settings_pool_create(struct master_settings_mmap *mmap);
+
 #undef DEF
 #define DEF(type, name) \
        SETTING_DEFINE_STRUCT_##type(#name, name, struct master_service_settings)
@@ -612,13 +614,8 @@ int master_service_settings_read(struct master_service *service,
                }
        }
        if (fd != -1) {
-               if (service->config_mmap != NULL) {
-                       i_assert(input->reload_config);
-                       master_settings_mmap_unref(&service->config_mmap);
-               }
-
+               master_settings_mmap_unref(&service->config_mmap);
                config_mmap = i_new(struct master_settings_mmap, 1);
-               service->config_mmap = config_mmap;
                config_mmap->refcount = 1;
                config_mmap->mmap_base =
                        mmap_ro_file(fd, &config_mmap->mmap_size);
@@ -627,21 +624,23 @@ int master_service_settings_read(struct master_service *service,
                if (config_mmap->mmap_size == 0)
                        i_fatal("Failed to read config: %s file size is empty", path);
 
+               service->config_mmap = config_mmap;
+               master_settings_mmap_ref(config_mmap);
+
                if (input->return_config_fd)
                        output_r->config_fd = fd;
                else
                        i_close_fd(&fd);
                env_remove(DOVECOT_CONFIG_FD_ENV);
+       } else if (service->config_mmap != NULL) {
+               config_mmap = service->config_mmap;
+               master_settings_mmap_ref(config_mmap);
        }
 
-       if (service->set_pool != NULL) {
-               if (service->set_parser != NULL)
-                       settings_parser_unref(&service->set_parser);
-               p_clear(service->set_pool);
-       } else {
-               service->set_pool =
-                       pool_alloconly_create("master service settings", 16384);
-       }
+       pool_unref(&service->set_pool);
+       if (service->set_parser != NULL)
+               settings_parser_unref(&service->set_parser);
+       service->set_pool = master_settings_pool_create(config_mmap);
 
        /* Create event for matching config filters */
        struct event *event = event_create(NULL);
@@ -683,10 +682,12 @@ int master_service_settings_read(struct master_service *service,
                        *error_r = t_strdup_printf(
                                "Failed to parse configuration: %s", error);
                        settings_parser_unref(&parser);
+                       master_settings_mmap_unref(&config_mmap);
                        event_unref(&event);
                        return -1;
                }
        }
+       master_settings_mmap_unref(&config_mmap);
        event_unref(&event);
 
        if (array_is_created(&service->config_overrides)) {
@@ -760,6 +761,115 @@ master_service_get_service_settings(struct master_service *service)
                &master_service_setting_parser_info);
 }
 
+struct master_settings_pool {
+       struct pool pool;
+       int refcount;
+
+       pool_t parent_pool;
+       struct master_settings_mmap *mmap;
+};
+
+static const char *pool_master_settings_get_name(pool_t pool)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       return pool_get_name(mpool->parent_pool);
+}
+
+static void pool_master_settings_ref(pool_t pool)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       i_assert(mpool->refcount > 0);
+       mpool->refcount++;
+}
+
+static void pool_master_settings_unref(pool_t *pool)
+{
+       struct master_settings_pool *mpool =
+               container_of(*pool, struct master_settings_pool, pool);
+
+       i_assert(mpool->refcount > 0);
+       *pool = NULL;
+       if (--mpool->refcount > 0)
+               return;
+
+       master_settings_mmap_unref(&mpool->mmap);
+       pool_unref(&mpool->parent_pool);
+}
+
+static void *pool_master_settings_malloc(pool_t pool, size_t size)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       return p_malloc(mpool->parent_pool, size);
+}
+
+static void pool_master_settings_free(pool_t pool, void *mem)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       p_free(mpool->parent_pool, mem);
+}
+
+static void *pool_master_settings_realloc(pool_t pool, void *mem,
+                                         size_t old_size, size_t new_size)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       return p_realloc(mpool->parent_pool, mem, old_size, new_size);
+}
+
+static void pool_master_settings_clear(pool_t pool ATTR_UNUSED)
+{
+       i_panic("pool_master_settings_clear() must not be called");
+}
+
+static size_t pool_master_settings_get_max_easy_alloc_size(pool_t pool)
+{
+       struct master_settings_pool *mpool =
+               container_of(pool, struct master_settings_pool, pool);
+
+       return p_get_max_easy_alloc_size(mpool->parent_pool);
+}
+
+static struct pool_vfuncs static_master_settings_pool_vfuncs = {
+       pool_master_settings_get_name,
+
+       pool_master_settings_ref,
+       pool_master_settings_unref,
+
+       pool_master_settings_malloc,
+       pool_master_settings_free,
+
+       pool_master_settings_realloc,
+
+       pool_master_settings_clear,
+       pool_master_settings_get_max_easy_alloc_size
+};
+
+static pool_t master_settings_pool_create(struct master_settings_mmap *mmap)
+{
+       struct master_settings_pool *mpool;
+       pool_t parent_pool =
+               pool_alloconly_create("master service settings", 256);
+
+       mpool = p_new(parent_pool, struct master_settings_pool, 1);
+       mpool->pool.v = &static_master_settings_pool_vfuncs;
+       mpool->pool.alloconly_pool = TRUE;
+       mpool->refcount = 1;
+       mpool->parent_pool = parent_pool;
+       mpool->mmap = mmap;
+       if (mmap != NULL)
+               master_settings_mmap_ref(mmap);
+       return &mpool->pool;
+}
+
 void *master_service_settings_get_root_set(struct master_service *service,
                                           const struct setting_parser_info *root)
 {
index 9087f964d4c9c15f7a06bec8f26cfe0ac5945ad2..39520d6ff56a9be1c5face26f0bd988b8a4a09bb 100644 (file)
@@ -1587,11 +1587,9 @@ static void master_service_deinit_real(struct master_service **_service)
        if (array_is_created(&service->config_overrides))
                array_free(&service->config_overrides);
 
-       if (service->set_parser != NULL) {
+       if (service->set_parser != NULL)
                settings_parser_unref(&service->set_parser);
-               pool_unref(&service->set_pool);
-       }
-       master_settings_mmap_unref(&service->config_mmap);
+       pool_unref(&service->set_pool); /* frees service->config_mmap */
        i_free(master_service_category_name);
        master_service_category.name = NULL;
        event_unregister_callback(master_service_event_callback);