]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Precompute composite atom types at config time
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 26 Nov 2025 12:33:26 +0000 (12:33 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 26 Nov 2025 12:33:26 +0000 (12:33 +0000)
Resolve ATOM_COMPOSITE vs ATOM_PLAIN for all composite atoms during
configuration phase instead of lazy evaluation at runtime. This
eliminates repeated hash lookups during expression evaluation.

- Add rspamd_composites_resolve_atom_types() function
- Call after process_dependencies() and before build_inverted_index()
- Sets comp_type and ncomp pointer for each atom upfront

src/libserver/composites/composites.cxx
src/libserver/composites/composites_internal.hxx
src/libserver/composites/composites_manager.cxx

index b9ab013da22e6d762309b3c0878ce7682083b854..dccd15cb8dfde9d57cbb63d9b59d13c588aca05c 100644 (file)
@@ -1043,6 +1043,43 @@ composites_metric_callback(struct rspamd_task *task)
        }
 }
 
+void rspamd_composites_resolve_atom_types(composites_manager *cm)
+{
+       auto resolve_callback = [](GNode *, rspamd_expression_atom_t *atom, gpointer ud) {
+               auto *manager = reinterpret_cast<composites_manager *>(ud);
+               auto *comp_atom = reinterpret_cast<rspamd_composite_atom *>(atom->data);
+
+               if (comp_atom == nullptr) {
+                       return;
+               }
+
+               if (comp_atom->comp_type != rspamd_composite_atom_type::ATOM_UNKNOWN) {
+                       /* Already resolved */
+                       return;
+               }
+
+               const auto *ncomp = manager->find(comp_atom->symbol);
+               if (ncomp != nullptr) {
+                       comp_atom->comp_type = rspamd_composite_atom_type::ATOM_COMPOSITE;
+                       comp_atom->ncomp = ncomp;
+               }
+               else {
+                       comp_atom->comp_type = rspamd_composite_atom_type::ATOM_PLAIN;
+                       comp_atom->ncomp = nullptr;
+               }
+       };
+
+       /* Process all first-pass composites */
+       for (auto *comp: cm->first_pass_composites) {
+               rspamd_expression_atom_foreach_ex(comp->expr, resolve_callback, cm);
+       }
+
+       /* Process all second-pass composites */
+       for (auto *comp: cm->second_pass_composites) {
+               rspamd_expression_atom_foreach_ex(comp->expr, resolve_callback, cm);
+       }
+}
+
 }// namespace rspamd::composites
 
 
index 032747e87263512cdf6e68e7a7edb12f8b8cc8a4..8cce77f2677737940234d6d704f6eb942c7542d8 100644 (file)
@@ -128,6 +128,13 @@ public:
        void build_inverted_index();
 };
 
+/**
+ * Precompute atom types (ATOM_COMPOSITE vs ATOM_PLAIN) for all composites.
+ * This eliminates lazy lookups during expression evaluation.
+ * Should be called after all composites are registered.
+ */
+void rspamd_composites_resolve_atom_types(composites_manager *cm);
+
 }// namespace rspamd::composites
 
 #endif//RSPAMD_COMPOSITES_INTERNAL_HXX
index 0f75e691e0a58d80dae1ce13b68be1f1039bcd02..df09cea1564f790dc436a2fd3406f8437f311afe 100644 (file)
@@ -611,5 +611,6 @@ void rspamd_composites_process_deps(void *cm_ptr, struct rspamd_config *cfg)
 {
        auto *cm = COMPOSITE_MANAGER_FROM_PTR(cm_ptr);
        cm->process_dependencies();
+       rspamd_composites_resolve_atom_types(cm);
        cm->build_inverted_index();
 }
\ No newline at end of file