struct cache_dependency {
- struct rspamd_symcache_item *item;
- gchar *sym;
- gint id;
+ struct rspamd_symcache_item *item; /* Real dependency */
+ gchar *sym; /* Symbolic dep name */
+ gint id; /* Real from */
+ gint vid; /* Virtual from */
};
struct delayed_cache_dependency {
cache->items_by_order = ord;
}
+static void
+rspamd_symcache_propagate_dep (struct rspamd_symcache *cache,
+ struct rspamd_symcache_item *it,
+ struct rspamd_symcache_item *dit)
+{
+ const guint *ids;
+ guint nids = 0;
+
+ ids = rspamd_symcache_get_allowed_settings_ids (cache, dit->symbol, &nids);
+
+ /* TODO: merge? */
+ if (nids > 0) {
+ msg_info_cache ("propagate allowed ids from %s to %s",
+ dit->symbol, it->symbol);
+
+ rspamd_symcache_set_allowed_settings_ids (cache, it->symbol, ids,
+ nids);
+ }
+
+ ids = rspamd_symcache_get_forbidden_settings_ids (cache, dit->symbol, &nids);
+
+ if (nids > 0) {
+ msg_info_cache ("propagate forbidden ids from %s to %s",
+ dit->symbol, it->symbol);
+
+ rspamd_symcache_set_forbidden_settings_ids (cache, it->symbol, ids,
+ nids);
+ }
+}
+
+static void
+rspamd_symcache_process_dep (struct rspamd_symcache *cache,
+ struct rspamd_symcache_item *it,
+ struct cache_dependency *dep)
+{
+ struct rspamd_symcache_item *dit = NULL, *vdit = NULL;
+ struct cache_dependency *rdep;
+
+ if (dep->id >= 0) {
+ dit = rspamd_symcache_find_filter (cache, dep->sym, true);
+ }
+
+ if (dep->vid >= 0) {
+ /* Case of the virtual symbol that depends on another (maybe virtual) symbol */
+ vdit = rspamd_symcache_find_filter (cache, dep->sym, false);
+ }
+ else {
+ vdit = dit;
+ }
+
+ if (dit != NULL) {
+ if (!dit->is_filter) {
+ /*
+ * Check sanity:
+ * - filters -> prefilter dependency is OK and always satisfied
+ * - postfilter -> (filter, prefilter) dep is ok
+ * - idempotent -> (any) dep is OK
+ *
+ * Otherwise, emit error
+ * However, even if everything is fine this dep is useless ¯\_(ツ)_/¯
+ */
+ gboolean ok_dep = FALSE;
+
+ if (it->is_filter) {
+ if (dit->type & SYMBOL_TYPE_PREFILTER) {
+ ok_dep = TRUE;
+ }
+ }
+ else if (it->type & SYMBOL_TYPE_POSTFILTER) {
+ if (dit->type & SYMBOL_TYPE_PREFILTER) {
+ ok_dep = TRUE;
+ }
+ }
+ else if (it->type & SYMBOL_TYPE_IDEMPOTENT) {
+ if (dit->type & (SYMBOL_TYPE_PREFILTER|SYMBOL_TYPE_POSTFILTER)) {
+ ok_dep = TRUE;
+ }
+ }
+ else if (it->type & SYMBOL_TYPE_PREFILTER) {
+ if (it->priority < dit->priority) {
+ /* Also OK */
+ ok_dep = TRUE;
+ }
+ }
+
+ if (!ok_dep) {
+ msg_err_cache ("cannot add dependency from %s on %s: invalid symbol types",
+ dep->sym, dit->symbol);
+
+ return;
+ }
+ }
+ else {
+ if (dit->id == it->id) {
+ msg_err_cache ("cannot add dependency on self: %s -> %s "
+ "(resolved to %s)",
+ it->symbol, dep->sym, dit->symbol);
+ } else {
+ rdep = rspamd_mempool_alloc (cache->static_pool,
+ sizeof (*rdep));
+
+ rdep->sym = dep->sym;
+ rdep->item = it;
+ rdep->id = it->id;
+ g_assert (dit->rdeps != NULL);
+ g_ptr_array_add (dit->rdeps, rdep);
+ dep->item = dit;
+ dep->id = dit->id;
+
+ msg_debug_cache ("add dependency from %d on %d", it->id,
+ dit->id);
+ }
+ }
+ }
+ else if (dep->id >= 0) {
+ msg_err_cache ("cannot find dependency on symbol %s for symbol %s",
+ dep->sym, it->symbol);
+
+ return;
+ }
+
+ if (vdit) {
+ /* Use virtual symbol to propagate deps */
+ rspamd_symcache_propagate_dep (cache, it, vdit);
+ }
+}
+
/* Sort items in logical order */
static void
rspamd_symcache_post_init (struct rspamd_symcache *cache)
{
- struct rspamd_symcache_item *it, *dit;
- struct cache_dependency *dep, *rdep;
+ struct rspamd_symcache_item *it, *vit;
+ struct cache_dependency *dep;
struct delayed_cache_dependency *ddep;
struct delayed_cache_condition *dcond;
GList *cur;
while (cur) {
ddep = cur->data;
+ vit = rspamd_symcache_find_filter (cache, ddep->from, false);
it = rspamd_symcache_find_filter (cache, ddep->from, true);
if (it == NULL) {
"%s is missing", ddep->from, ddep->to, ddep->from);
}
else {
- msg_debug_cache ("delayed between %s(%d) -> %s", ddep->from,
- it->id, ddep->to);
- rspamd_symcache_add_dependency (cache, it->id, ddep->to);
+ msg_debug_cache ("delayed between %s(%d:%d) -> %s", ddep->from,
+ it->id, vit->id, ddep->to);
+ rspamd_symcache_add_dependency (cache, it->id, ddep->to, vit->id);
}
cur = g_list_next (cur);
PTR_ARRAY_FOREACH (cache->items_by_id, i, it) {
PTR_ARRAY_FOREACH (it->deps, j, dep) {
- dit = rspamd_symcache_find_filter (cache, dep->sym, true);
-
- if (dit != NULL) {
- if (!dit->is_filter) {
- msg_err_cache ("cannot depend on non filter symbol "
- "(%s wants to add dependency on %s)",
- dep->sym, dit->symbol);
- }
- else {
- if (dit->id == i) {
- msg_err_cache ("cannot add dependency on self: %s -> %s "
- "(resolved to %s)",
- it->symbol, dep->sym, dit->symbol);
- } else {
- rdep = rspamd_mempool_alloc (cache->static_pool,
- sizeof (*rdep));
-
- rdep->sym = dep->sym;
- rdep->item = it;
- rdep->id = i;
- g_assert (dit->rdeps != NULL);
- g_ptr_array_add (dit->rdeps, rdep);
- dep->item = dit;
- dep->id = dit->id;
-
- msg_debug_cache ("add dependency from %d on %d", it->id,
- dit->id);
- }
- }
- }
- else {
- msg_err_cache ("cannot find dependency on symbol %s for symbol %s",
- dep->sym, it->symbol);
- }
+ rspamd_symcache_process_dep (cache, it, dep);
}
if (it->deps) {
cache->used_items, item->id);
}
- if (item->is_filter) {
- /* Only plain filters can have deps and rdeps */
- item->deps = g_ptr_array_new ();
- item->rdeps = g_ptr_array_new ();
- rspamd_mempool_add_destructor (cache->static_pool,
- rspamd_ptr_array_free_hard, item->deps);
- rspamd_mempool_add_destructor (cache->static_pool,
- rspamd_ptr_array_free_hard, item->rdeps);
- }
+ item->deps = g_ptr_array_new ();
+ item->rdeps = g_ptr_array_new ();
+ rspamd_mempool_add_destructor (cache->static_pool,
+ rspamd_ptr_array_free_hard, item->deps);
+ rspamd_mempool_add_destructor (cache->static_pool,
+ rspamd_ptr_array_free_hard, item->rdeps);
if (name != NULL) {
g_hash_table_insert (cache->items_by_symbol, item->symbol, item);
void
rspamd_symcache_add_dependency (struct rspamd_symcache *cache,
- gint id_from, const gchar *to)
+ gint id_from, const gchar *to,
+ gint virtual_id_from)
{
- struct rspamd_symcache_item *source;
+ struct rspamd_symcache_item *source, *vsource;
struct cache_dependency *dep;
g_assert (id_from >= 0 && id_from < (gint)cache->items_by_id->len);
dep->sym = rspamd_mempool_strdup (cache->static_pool, to);
/* Will be filled later */
dep->item = NULL;
+ dep->vid = -1;
g_ptr_array_add (source->deps, dep);
+
+ if (id_from != virtual_id_from) {
+ /* We need that for settings id propagation */
+ vsource = g_ptr_array_index (cache->items_by_id, virtual_id_from);
+ dep = rspamd_mempool_alloc (cache->static_pool, sizeof (*dep));
+ dep->vid = id_from;
+ dep->id = -1;
+ dep->sym = rspamd_mempool_strdup (cache->static_pool, to);
+ /* Will be filled later */
+ dep->item = NULL;
+ g_ptr_array_add (vsource->deps, dep);
+ }
}
void