gint rspamd_symbols_cache_add_symbol (struct symbols_cache *cache, const gchar *name, double weight, gint priority, symbol_func_t func, gpointer user_data, enum rspamd_symbol_type type, gint parent) { struct cache_item *item = NULL; g_assert (cache != NULL); if (name == NULL && type != SYMBOL_TYPE_CALLBACK) { msg_warn ("no name for non-callback symbol!"); } else if (type == SYMBOL_TYPE_VIRTUAL && parent == -1) { msg_warn ("no parent symbol is associated with virtual symbol %s", name); } if (name != NULL) { if (g_hash_table_lookup (cache->items_by_symbol, name) != NULL) { msg_err ("skip duplicate symbol registration for %s", name); return -1; } } item = rspamd_mempool_alloc0_shared (cache->static_pool, sizeof (struct cache_item)); /* * We do not share cd to skip locking, instead we'll just calculate it on * save or accumulate */ item->cd = rspamd_mempool_alloc0 (cache->static_pool, sizeof (struct counter_data)); if (name != NULL) { item->symbol = rspamd_mempool_strdup (cache->static_pool, name); } item->func = func; item->user_data = user_data; item->priority = priority; item->type = type; item->weight = weight; if (item->weight < 0 && item->priority == 0) { /* Make priority for negative weighted symbols */ item->priority = 1; } item->id = cache->used_items; item->parent = parent; cache->used_items ++; msg_debug ("used items: %d, added symbol: %s", cache->used_items, name); rspamd_set_counter (item, 0); g_ptr_array_add (cache->items_by_id, item); g_ptr_array_add (cache->items_by_order, item); 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); } return item->id; }
static gboolean rspamd_symbols_cache_check_symbol (struct rspamd_task *task, struct symbols_cache *cache, struct cache_item *item, struct cache_savepoint *checkpoint, gdouble *total_diff) { guint pending_before, pending_after; double t1, t2; gdouble diff; struct rspamd_task **ptask; lua_State *L; gboolean check = TRUE; const gdouble slow_diff_limit = 1e5; if (item->type & (SYMBOL_TYPE_NORMAL|SYMBOL_TYPE_CALLBACK)) { g_assert (item->func != NULL); /* Check has been started */ setbit (checkpoint->processed_bits, item->id * 2); if (RSPAMD_TASK_IS_EMPTY (task) && !(item->type & SYMBOL_TYPE_EMPTY)) { check = FALSE; } else if (item->condition_cb != -1) { /* We also executes condition callback to check if we need this symbol */ L = task->cfg->lua_state; lua_rawgeti (L, LUA_REGISTRYINDEX, item->condition_cb); ptask = lua_newuserdata (L, sizeof (struct rspamd_task *)); rspamd_lua_setclass (L, "rspamd{task}", -1); *ptask = task; if (lua_pcall (L, 1, 1, 0) != 0) { msg_info_task ("call to condition for %s failed: %s", item->symbol, lua_tostring (L, -1)); lua_pop (L, 1); } else { check = lua_toboolean (L, -1); lua_pop (L, 1); } } if (check) { t1 = rspamd_get_ticks (); pending_before = rspamd_session_events_pending (task->s); /* Watch for events appeared */ rspamd_session_watch_start (task->s, rspamd_symbols_cache_watcher_cb, item); msg_debug_task ("execute %s, %d", item->symbol, item->id); item->func (task, item->user_data); t2 = rspamd_get_ticks (); diff = (t2 - t1) * 1e6; if (total_diff) { *total_diff += diff; } if (diff > slow_diff_limit) { msg_info_task ("slow rule: %s: %d ms", item->symbol, (gint)(diff / 1000.)); } rspamd_set_counter (item, diff); rspamd_session_watch_stop (task->s); pending_after = rspamd_session_events_pending (task->s); if (pending_before == pending_after) { /* No new events registered */ setbit (checkpoint->processed_bits, item->id * 2 + 1); return TRUE; } return FALSE; } else { msg_debug_task ("skipping check of %s as its condition is false", item->symbol); setbit (checkpoint->processed_bits, item->id * 2 + 1); return TRUE; } } else { setbit (checkpoint->processed_bits, item->id * 2); setbit (checkpoint->processed_bits, item->id * 2 + 1); return TRUE; } }