]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Minor] Use more efficient approach for iterations
authorVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 7 Jul 2025 14:45:43 +0000 (15:45 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 7 Jul 2025 14:45:43 +0000 (15:45 +0100)
src/hs_helper.c
src/libserver/maps/map.c
src/libserver/re_cache.c
src/libserver/re_cache.h
src/lua/lua_config.c

index c5a42ad12a13aa769678a2f62a4d8b95e875ec1b..f3edbd64bb6e1049455e3007e3a300ecacf5830a 100644 (file)
@@ -449,11 +449,24 @@ rspamd_rs_compile(struct hs_helper_ctx *ctx, struct rspamd_worker *worker,
                return TRUE;
        }
 
-       /* Get all scope names */
-       char **scope_names = rspamd_re_cache_get_scope_names(ctx->cfg->re_cache);
+       /* Count scopes and prepare compilation data */
+       struct rspamd_re_cache *scope;
+       unsigned int total_scopes = 0;
+
+       /* Count valid scopes first */
+       for (scope = rspamd_re_cache_scope_first(ctx->cfg->re_cache);
+                scope != NULL;
+                scope = rspamd_re_cache_scope_next(scope)) {
+               const char *scope_name = rspamd_re_cache_scope_name(scope);
+               const char *scope_for_check = (strcmp(scope_name, "default") == 0) ? NULL : scope_name;
+
+               if (rspamd_re_cache_is_loaded(ctx->cfg->re_cache, scope_for_check)) {
+                       total_scopes++;
+               }
+       }
 
-       if (!scope_names) {
-               /* Failed to get scope names, use standard compilation for default scope */
+       if (total_scopes == 0) {
+               /* No loaded scopes, use standard compilation for default scope */
                struct rspamd_hs_helper_single_compile_cbdata *single_cbd =
                        g_malloc0(sizeof(*single_cbd));
                single_cbd->worker = worker;
@@ -474,41 +487,28 @@ rspamd_rs_compile(struct hs_helper_ctx *ctx, struct rspamd_worker *worker,
        compile_cbd->worker = worker;
        compile_cbd->ctx = ctx;
        compile_cbd->total_compiled = 0;
-       compile_cbd->scopes_remaining = g_strv_length(scope_names);
+       compile_cbd->scopes_remaining = total_scopes;
        compile_cbd->forced = forced;
        compile_cbd->workers_ready = ctx->workers_ready;
 
-       /* Compile each scope */
-       for (const char **cur_scope = scope_names; *cur_scope; cur_scope++) {
-               const char *scope = strcmp(*cur_scope, "default") == 0 ? NULL : *cur_scope;
-               struct rspamd_re_cache *scope_cache = rspamd_re_cache_find_scope(ctx->cfg->re_cache, scope);
+       /* Compile each loaded scope */
+       for (scope = rspamd_re_cache_scope_first(ctx->cfg->re_cache);
+                scope != NULL;
+                scope = rspamd_re_cache_scope_next(scope)) {
+               const char *scope_name = rspamd_re_cache_scope_name(scope);
+               const char *scope_for_compile = (strcmp(scope_name, "default") == 0) ? NULL : scope_name;
 
-               if (scope_cache && rspamd_re_cache_is_loaded(ctx->cfg->re_cache, scope)) {
-                       rspamd_re_cache_compile_hyperscan_scoped_single(scope_cache, scope,
+               if (rspamd_re_cache_is_loaded(ctx->cfg->re_cache, scope_for_compile)) {
+                       rspamd_re_cache_compile_hyperscan_scoped_single(scope, scope_for_compile,
                                                                                                                        ctx->hs_dir, ctx->max_time, !forced,
                                                                                                                        ctx->event_loop,
                                                                                                                        rspamd_rs_compile_scoped_cb,
                                                                                                                        compile_cbd);
                }
                else {
-                       /* Scope not loaded, skip it */
-                       compile_cbd->scopes_remaining--;
-                       msg_debug("skipping unloaded scope: %s", scope ? scope : "default");
-
-                       /* Check if we're done */
-                       if (compile_cbd->scopes_remaining == 0) {
-                               /* No scopes to compile, send final notification immediately */
-                               if (compile_cbd->workers_ready) {
-                                       rspamd_rs_send_final_notification(compile_cbd);
-                               }
-                               else {
-                                       ctx->loaded = TRUE;
-                               }
-                       }
+                       msg_debug("skipping unloaded scope: %s", scope_name);
                }
        }
-
-       g_strfreev(scope_names);
        return TRUE;
 }
 
index 8ebf55317bd5352aa64ef9f1da34479f1e756c67..6de694eb3ccf90835f8211b361cc48ab786c2dcf 100644 (file)
@@ -3376,35 +3376,28 @@ void rspamd_map_trigger_hyperscan_compilation(struct rspamd_map *map)
                return;
        }
 
-       /* Get scope names and compile those that are loaded */
-       char **scope_names = rspamd_re_cache_get_scope_names(map->cfg->re_cache),
-                **cur_scope;
-
-       if (scope_names) {
-               for (cur_scope = scope_names; *cur_scope; cur_scope++) {
-                       const char *scope = strcmp(*cur_scope, "default") == 0 ? NULL : *cur_scope;
-
-                       /* Only compile loaded scopes */
-                       if (rspamd_re_cache_is_loaded(map->cfg->re_cache, scope)) {
-                               struct rspamd_re_cache *scope_cache = rspamd_re_cache_find_scope(map->cfg->re_cache, scope);
-
-                               if (scope_cache) {
-                                       msg_info_map("triggering hyperscan compilation for scope: %s after map update",
-                                                                scope ? scope : "default");
-
-                                       /* Use default settings for compilation */
-                                       rspamd_re_cache_compile_hyperscan_scoped_single(scope_cache, scope,
-                                                                                                                                       map->cfg->hs_cache_dir ? map->cfg->hs_cache_dir : RSPAMD_DBDIR "/",
-                                                                                                                                       1.0,   /* max_time */
-                                                                                                                                       FALSE, /* silent */
-                                                                                                                                       worker->ctx ? ((struct rspamd_abstract_worker_ctx *) worker->ctx)->event_loop : NULL,
-                                                                                                                                       NULL,  /* callback */
-                                                                                                                                       NULL); /* cbdata */
-                               }
-                       }
+       /* Iterate through scopes and compile those that are loaded */
+       struct rspamd_re_cache *scope;
+
+       for (scope = rspamd_re_cache_scope_first(map->cfg->re_cache);
+                scope != NULL;
+                scope = rspamd_re_cache_scope_next(scope)) {
+               const char *scope_name = rspamd_re_cache_scope_name(scope);
+               const char *scope_for_check = (strcmp(scope_name, "default") == 0) ? NULL : scope_name;
+
+               /* Only compile loaded scopes */
+               if (rspamd_re_cache_is_loaded(map->cfg->re_cache, scope_for_check)) {
+                       msg_info_map("triggering hyperscan compilation for scope: %s after map update",
+                                                scope_name);
+
+                       /* Use default settings for compilation */
+                       rspamd_re_cache_compile_hyperscan_scoped_single(scope, scope_for_check,
+                                                                                                                       map->cfg->hs_cache_dir ? map->cfg->hs_cache_dir : RSPAMD_DBDIR "/",
+                                                                                                                       1.0,   /* max_time */
+                                                                                                                       FALSE, /* silent */
+                                                                                                                       worker->ctx ? ((struct rspamd_abstract_worker_ctx *) worker->ctx)->event_loop : NULL,
+                                                                                                                       NULL,  /* callback */
+                                                                                                                       NULL); /* cbdata */
                }
-
-               /* Clean up scope names */
-               g_strfreev(scope_names);
        }
 }
index 22b9b3b59f4dcfaba11d1327b669c76c626a6774..5313e157a09927af3f870468d661777972b87b56 100644 (file)
@@ -3204,6 +3204,53 @@ unsigned int rspamd_re_cache_count_scopes(struct rspamd_re_cache *cache_head)
        return count;
 }
 
+struct rspamd_re_cache *rspamd_re_cache_scope_first(struct rspamd_re_cache *cache_head)
+{
+       return cache_head;
+}
+
+struct rspamd_re_cache *rspamd_re_cache_scope_next(struct rspamd_re_cache *current)
+{
+       return current ? current->next : NULL;
+}
+
+const char *rspamd_re_cache_scope_name(struct rspamd_re_cache *scope)
+{
+       if (!scope) {
+               return "unknown";
+       }
+
+       return scope->scope ? scope->scope : "default";
+}
+
+void rspamd_re_cache_scope_set_flags(struct rspamd_re_cache *scope, unsigned int flags)
+{
+       if (scope) {
+               scope->flags |= flags;
+       }
+}
+
+void rspamd_re_cache_scope_clear_flags(struct rspamd_re_cache *scope, unsigned int flags)
+{
+       if (scope) {
+               scope->flags &= ~flags;
+       }
+}
+
+unsigned int rspamd_re_cache_scope_get_flags(struct rspamd_re_cache *scope)
+{
+       return scope ? scope->flags : 0;
+}
+
+gboolean rspamd_re_cache_scope_is_loaded(struct rspamd_re_cache *scope)
+{
+       if (!scope) {
+               return FALSE;
+       }
+
+       return (scope->flags & RSPAMD_RE_CACHE_FLAG_LOADED) != 0;
+}
+
 void rspamd_re_cache_set_flags(struct rspamd_re_cache *cache_head, const char *scope, unsigned int flags)
 {
        struct rspamd_re_cache *target;
@@ -3254,43 +3301,6 @@ gboolean rspamd_re_cache_is_loaded(struct rspamd_re_cache *cache_head, const cha
        return (flags & RSPAMD_RE_CACHE_FLAG_LOADED) != 0;
 }
 
-char **rspamd_re_cache_get_scope_names(struct rspamd_re_cache *cache_head)
-{
-       struct rspamd_re_cache *cur;
-       char **names = NULL;
-       unsigned int i = 0, count = 0;
-
-       if (!cache_head) {
-               return NULL;
-       }
-
-       /* First count scopes */
-       DL_COUNT(cache_head, cur, count);
-
-       if (count == 0) {
-               return NULL;
-       }
-
-       /* Allocate array with extra slot for NULL terminator */
-       names = g_malloc(sizeof(char *) * (count + 1));
-
-       /* Fill array */
-       DL_FOREACH(cache_head, cur)
-       {
-               if (cur->scope) {
-                       names[i] = g_strdup(cur->scope);
-               }
-               else {
-                       names[i] = g_strdup("default");
-               }
-               i++;
-       }
-
-       /* NULL terminate the array for g_strfreev compatibility */
-       names[count] = NULL;
-
-       return names;
-}
 
 static gboolean
 rspamd_re_cache_create_scope_lock(const char *cache_dir, const char *scope, int *lock_fd)
index 5ae9ecdb7259f3a09c1b7aaf83ea3eca65e939e4..c5c8627d89008cbd9ff7cbd8ee46dc7e2e350559 100644 (file)
@@ -308,20 +308,69 @@ struct rspamd_re_cache *rspamd_re_cache_find_scope(struct rspamd_re_cache *cache
  */
 gboolean rspamd_re_cache_remove_scope(struct rspamd_re_cache **cache_head, const char *scope);
 
+/**
+ * Get array of scope names from the cache list
+ * @param cache_head head of cache list
+ * @return NULL-terminated array of scope names (must be freed with g_strfreev), or NULL if no scopes
+ */
+char **rspamd_re_cache_get_scope_names(struct rspamd_re_cache *cache_head);
+
 /**
  * Count the number of scopes in the cache list
  */
 unsigned int rspamd_re_cache_count_scopes(struct rspamd_re_cache *cache_head);
 
 /**
- * Get array of scope names from the cache list
+ * Get the first scope in the cache list for iteration
  * @param cache_head head of cache list
- * @return NULL-terminated array of scope names (must be freed with g_strfreev), or NULL if no scopes
+ * @return first scope, or NULL if no scopes
  */
-char **rspamd_re_cache_get_scope_names(struct rspamd_re_cache *cache_head);
+struct rspamd_re_cache *rspamd_re_cache_scope_first(struct rspamd_re_cache *cache_head);
+
+/**
+ * Get the next scope in iteration
+ * @param current current scope
+ * @return next scope, or NULL if at end
+ */
+struct rspamd_re_cache *rspamd_re_cache_scope_next(struct rspamd_re_cache *current);
+
+/**
+ * Get the scope name (for display/logging purposes)
+ * @param scope the scope
+ * @return scope name ("default" for NULL scope name), never returns NULL
+ */
+const char *rspamd_re_cache_scope_name(struct rspamd_re_cache *scope);
+
+/**
+ * Set flags on a scope (efficient version that works directly on scope object)
+ * @param scope the scope object (from iterator)
+ * @param flags flags to set
+ */
+void rspamd_re_cache_scope_set_flags(struct rspamd_re_cache *scope, unsigned int flags);
+
+/**
+ * Clear flags on a scope (efficient version that works directly on scope object)
+ * @param scope the scope object (from iterator)
+ * @param flags flags to clear
+ */
+void rspamd_re_cache_scope_clear_flags(struct rspamd_re_cache *scope, unsigned int flags);
+
+/**
+ * Get flags from a scope (efficient version that works directly on scope object)
+ * @param scope the scope object (from iterator)
+ * @return flags value
+ */
+unsigned int rspamd_re_cache_scope_get_flags(struct rspamd_re_cache *scope);
+
+/**
+ * Check if a scope is loaded (efficient version that works directly on scope object)
+ * @param scope the scope object (from iterator)
+ * @return TRUE if scope is loaded
+ */
+gboolean rspamd_re_cache_scope_is_loaded(struct rspamd_re_cache *scope);
 
 /**
- * Set flags for a specific scope
+ * Set flags for a specific scope (legacy function - less efficient, searches by name)
  * @param cache_head head of cache list
  * @param scope scope name (NULL for default scope)
  * @param flags flags to set
@@ -329,7 +378,7 @@ char **rspamd_re_cache_get_scope_names(struct rspamd_re_cache *cache_head);
 void rspamd_re_cache_set_flags(struct rspamd_re_cache *cache_head, const char *scope, unsigned int flags);
 
 /**
- * Clear flags for a specific scope
+ * Clear flags for a specific scope (legacy function - less efficient, searches by name)
  * @param cache_head head of cache list
  * @param scope scope name (NULL for default scope)
  * @param flags flags to clear
@@ -337,7 +386,7 @@ void rspamd_re_cache_set_flags(struct rspamd_re_cache *cache_head, const char *s
 void rspamd_re_cache_clear_flags(struct rspamd_re_cache *cache_head, const char *scope, unsigned int flags);
 
 /**
- * Get flags for a specific scope
+ * Get flags for a specific scope (legacy function - less efficient, searches by name)
  * @param cache_head head of cache list
  * @param scope scope name (NULL for default scope)
  * @return flags value
@@ -345,7 +394,7 @@ void rspamd_re_cache_clear_flags(struct rspamd_re_cache *cache_head, const char
 unsigned int rspamd_re_cache_get_flags(struct rspamd_re_cache *cache_head, const char *scope);
 
 /**
- * Check if a scope is loaded
+ * Check if a scope is loaded (legacy function - less efficient, searches by name)
  * @param cache_head head of cache list
  * @param scope scope name (NULL for default scope)
  * @return TRUE if scope is loaded and ready for use
index 0fe98b2edb29d4968d0141e8a79d4d51e8ffa79f..5416eae3cf86aea42e1da4aa0da6c233de0ab8fc 100644 (file)
@@ -5268,21 +5268,18 @@ lua_config_list_regexp_scopes(lua_State *L)
        struct rspamd_config *cfg = lua_check_config(L, 1);
 
        if (cfg) {
-               char **scope_names, **cur_scope;
-               unsigned int i;
-
-               scope_names = rspamd_re_cache_get_scope_names(cfg->re_cache);
+               struct rspamd_re_cache *scope;
+               unsigned int i = 0;
 
                lua_newtable(L);
 
-               if (scope_names) {
-                       for (cur_scope = scope_names, i = 0; *cur_scope != NULL; cur_scope++, i++) {
-                               lua_pushinteger(L, i + 1);
-                               lua_pushstring(L, scope_names[i]);
-                               lua_settable(L, -3);
-                       }
-
-                       g_strfreev(scope_names);
+               for (scope = rspamd_re_cache_scope_first(cfg->re_cache);
+                        scope != NULL;
+                        scope = rspamd_re_cache_scope_next(scope)) {
+                       lua_pushinteger(L, i + 1);
+                       lua_pushstring(L, rspamd_re_cache_scope_name(scope));
+                       lua_settable(L, -3);
+                       i++;
                }
        }
        else {