struct rspamd_stat_cache { | struct rspamd_stat_cache { | ||||
const char *name; | const char *name; | ||||
gpointer (*init)(struct rspamd_stat_ctx *ctx, struct rspamd_config *cfg); | |||||
gpointer (*init)(struct rspamd_stat_ctx *ctx, | |||||
struct rspamd_config *cfg, const ucl_object_t *cf); | |||||
gint (*process)(struct rspamd_task *task, | gint (*process)(struct rspamd_task *task, | ||||
gboolean is_spam, | gboolean is_spam, | ||||
gpointer ctx); | gpointer ctx); | ||||
}; | }; | ||||
gpointer rspamd_stat_cache_sqlite3_init(struct rspamd_stat_ctx *ctx, | gpointer rspamd_stat_cache_sqlite3_init(struct rspamd_stat_ctx *ctx, | ||||
struct rspamd_config *cfg); | |||||
struct rspamd_config *cfg, | |||||
const ucl_object_t *cf); | |||||
gint rspamd_stat_cache_sqlite3_process ( | gint rspamd_stat_cache_sqlite3_process ( | ||||
struct rspamd_task *task, | struct rspamd_task *task, | ||||
gboolean is_spam, gpointer c); | gboolean is_spam, gpointer c); |
gpointer | gpointer | ||||
rspamd_stat_cache_sqlite3_init(struct rspamd_stat_ctx *ctx, | rspamd_stat_cache_sqlite3_init(struct rspamd_stat_ctx *ctx, | ||||
struct rspamd_config *cfg) | |||||
struct rspamd_config *cfg, | |||||
const ucl_object_t *cf) | |||||
{ | { | ||||
struct rspamd_stat_sqlite3_ctx *new = NULL; | struct rspamd_stat_sqlite3_ctx *new = NULL; | ||||
struct rspamd_classifier_config *clf; | |||||
const ucl_object_t *obj, *elt; | |||||
GList *cur; | |||||
const ucl_object_t *elt; | |||||
gchar dbpath[PATH_MAX]; | gchar dbpath[PATH_MAX]; | ||||
const gchar *path; | |||||
sqlite3 *sqlite; | sqlite3 *sqlite; | ||||
gboolean has_sqlite_cache = FALSE; | |||||
GError *err = NULL; | GError *err = NULL; | ||||
rspamd_snprintf (dbpath, sizeof (dbpath), SQLITE_CACHE_PATH); | |||||
cur = cfg->classifiers; | |||||
while (cur) { | |||||
clf = cur->data; | |||||
if (cf) { | |||||
elt = ucl_object_find_key (cf, "path"); | |||||
obj = ucl_object_find_key (clf->opts, "cache"); | |||||
/* Sqlite3 cache is the default learn cache method */ | |||||
if (obj == NULL) { | |||||
has_sqlite_cache = TRUE; | |||||
break; | |||||
if (elt != NULL) { | |||||
path = ucl_object_tostring (elt); | |||||
} | |||||
else { | |||||
path = SQLITE_CACHE_PATH; | |||||
} | } | ||||
else if (ucl_object_type (obj) == UCL_OBJECT) { | |||||
elt = ucl_object_find_key (obj, "name"); | |||||
} | |||||
if (ucl_object_type (elt) == UCL_STRING && | |||||
g_ascii_strcasecmp (ucl_object_tostring (elt), "sqlite3") == 0) { | |||||
rspamd_snprintf (dbpath, sizeof (dbpath), "%s", path); | |||||
has_sqlite_cache = TRUE; | |||||
elt = ucl_object_find_key (obj, "path"); | |||||
if (elt != NULL && ucl_object_type (elt) == UCL_STRING) { | |||||
rspamd_snprintf (dbpath, sizeof (dbpath), "%s", | |||||
ucl_object_tostring (elt)); | |||||
} | |||||
} | |||||
} | |||||
sqlite = rspamd_sqlite3_open_or_create (cfg->cfg_pool, | |||||
dbpath, create_tables_sql, &err); | |||||
cur = g_list_next (cur); | |||||
if (sqlite == NULL) { | |||||
msg_err ("cannot open sqlite3 cache: %e", err); | |||||
g_error_free (err); | |||||
err = NULL; | |||||
} | } | ||||
else { | |||||
new = g_slice_alloc (sizeof (*new)); | |||||
new->db = sqlite; | |||||
new->prstmt = rspamd_sqlite3_init_prstmt (sqlite, prepared_stmts, | |||||
RSPAMD_STAT_CACHE_MAX, &err); | |||||
if (has_sqlite_cache) { | |||||
sqlite = rspamd_sqlite3_open_or_create (cfg->cfg_pool, | |||||
dbpath, create_tables_sql, &err); | |||||
if (sqlite == NULL) { | |||||
msg_err_config ("cannot open sqlite3 cache: %e", err); | |||||
if (new->prstmt == NULL) { | |||||
msg_err ("cannot open sqlite3 cache: %e", err); | |||||
g_error_free (err); | g_error_free (err); | ||||
err = NULL; | err = NULL; | ||||
} | |||||
else { | |||||
new = g_slice_alloc (sizeof (*new)); | |||||
new->db = sqlite; | |||||
new->prstmt = rspamd_sqlite3_init_prstmt (sqlite, prepared_stmts, | |||||
RSPAMD_STAT_CACHE_MAX, &err); | |||||
if (new->prstmt == NULL) { | |||||
msg_err_config ("cannot open sqlite3 cache: %e", err); | |||||
g_error_free (err); | |||||
err = NULL; | |||||
sqlite3_close (sqlite); | |||||
g_slice_free1 (sizeof (*new), new); | |||||
new = NULL; | |||||
} | |||||
sqlite3_close (sqlite); | |||||
g_slice_free1 (sizeof (*new), new); | |||||
new = NULL; | |||||
} | } | ||||
} | } | ||||
struct rspamd_statfile_config *stf; | struct rspamd_statfile_config *stf; | ||||
struct rspamd_stat_backend *bk; | struct rspamd_stat_backend *bk; | ||||
struct rspamd_statfile *st; | struct rspamd_statfile *st; | ||||
struct rspamd_classifier *cl; | |||||
const ucl_object_t *cache_obj = NULL, *cache_name_obj; | |||||
const gchar *cache_name = NULL; | |||||
if (stat_ctx == NULL) { | if (stat_ctx == NULL) { | ||||
stat_ctx = g_slice_alloc0 (sizeof (*stat_ctx)); | stat_ctx = g_slice_alloc0 (sizeof (*stat_ctx)); | ||||
} | } | ||||
stat_ctx->backends = stat_backends; | |||||
stat_ctx->backends_subrs = stat_backends; | |||||
stat_ctx->backends_count = G_N_ELEMENTS (stat_backends); | stat_ctx->backends_count = G_N_ELEMENTS (stat_backends); | ||||
stat_ctx->classifiers = stat_classifiers; | |||||
stat_ctx->classifiers_subrs = stat_classifiers; | |||||
stat_ctx->classifiers_count = G_N_ELEMENTS (stat_classifiers); | stat_ctx->classifiers_count = G_N_ELEMENTS (stat_classifiers); | ||||
stat_ctx->tokenizers = stat_tokenizers; | |||||
stat_ctx->tokenizers_subrs = stat_tokenizers; | |||||
stat_ctx->tokenizers_count = G_N_ELEMENTS (stat_tokenizers); | stat_ctx->tokenizers_count = G_N_ELEMENTS (stat_tokenizers); | ||||
stat_ctx->caches = stat_caches; | |||||
stat_ctx->caches_subrs = stat_caches; | |||||
stat_ctx->caches_count = G_N_ELEMENTS (stat_caches); | stat_ctx->caches_count = G_N_ELEMENTS (stat_caches); | ||||
stat_ctx->cfg = cfg; | stat_ctx->cfg = cfg; | ||||
stat_ctx->statfiles = g_ptr_array_new (); | |||||
stat_ctx->classifiers = g_ptr_array_new (); | |||||
REF_RETAIN (stat_ctx->cfg); | REF_RETAIN (stat_ctx->cfg); | ||||
/* Create statfiles from the classifiers */ | /* Create statfiles from the classifiers */ | ||||
clf->tokenizer, NULL); | clf->tokenizer, NULL); | ||||
} | } | ||||
cl = g_slice_alloc0 (sizeof (*cl)); | |||||
cl->cfg = clf; | |||||
cl->statfiles_ids = g_array_new (FALSE, FALSE, sizeof (gint)); | |||||
/* Init classifier cache */ | |||||
if (clf->opts) { | |||||
cache_obj = ucl_object_find_key (clf->opts, "cache"); | |||||
if (cache_obj) { | |||||
cache_name_obj = ucl_object_find_key (cache_obj, "name"); | |||||
} | |||||
if (cache_name_obj) { | |||||
cache_name = ucl_object_tostring (cache_name_obj); | |||||
} | |||||
} | |||||
cl->cache = rspamd_stat_get_cache (cache_name); | |||||
g_assert (cl->cache != NULL); | |||||
cl->cachecf = cl->cache->init (stat_ctx, cfg, cache_obj); | |||||
curst = clf->statfiles; | curst = clf->statfiles; | ||||
while (curst) { | while (curst) { | ||||
stf = curst->data; | stf = curst->data; | ||||
st = g_slice_alloc0 (sizeof (*st)); | st = g_slice_alloc0 (sizeof (*st)); | ||||
st->clcf = clf; | |||||
st->classifier = cl; | |||||
st->stcf = stf; | st->stcf = stf; | ||||
st->tkcf = stat_ctx->tkcf; | |||||
st->bkcf = stat_ctx->backends[i].init (stat_ctx, cfg, st); | |||||
msg_debug_config ("added backend %s", stat_ctx->backends[i].name); | |||||
st->bkcf = stat_ctx->backends_subrs[i].init (stat_ctx, cfg, st); | |||||
msg_debug_config ("added backend %s", | |||||
stat_ctx->backends_subrs[i].name); | |||||
if (st->bkcf == NULL) { | if (st->bkcf == NULL) { | ||||
msg_err_config ("cannot init backend %s for statfile %s", | msg_err_config ("cannot init backend %s for statfile %s", | ||||
g_slice_free1 (sizeof (*st), st); | g_slice_free1 (sizeof (*st), st); | ||||
} | } | ||||
else { | else { | ||||
st->id = stat_ctx->statfiles->len; | |||||
g_ptr_array_add (stat_ctx->statfiles, st); | g_ptr_array_add (stat_ctx->statfiles, st); | ||||
g_array_append_val (cl->statfiles_ids, st->id); | |||||
} | } | ||||
curst = curst->next; | curst = curst->next; | ||||
} | } | ||||
cur = cur->next; | |||||
} | |||||
g_ptr_array_add (stat_ctx->classifiers, cl); | |||||
/* Init caches */ | |||||
for (i = 0; i < stat_ctx->caches_count; i ++) { | |||||
stat_ctx->caches[i].ctx = stat_ctx->caches[i].init (stat_ctx, cfg); | |||||
msg_debug_config ("added cache %s", stat_ctx->caches[i].name); | |||||
cur = cur->next; | |||||
} | } | ||||
} | } | ||||
g_assert (stat_ctx != NULL); | g_assert (stat_ctx != NULL); | ||||
for (i = 0; i < stat_ctx->backends_count; i ++) { | for (i = 0; i < stat_ctx->backends_count; i ++) { | ||||
if (stat_ctx->backends[i].close != NULL) { | |||||
stat_ctx->backends[i].close (stat_ctx->backends[i].ctx); | |||||
msg_debug_config ("closed backend %s", stat_ctx->backends[i].name); | |||||
if (stat_ctx->backends_subrs[i].close != NULL) { | |||||
stat_ctx->backends_subrs[i].close (stat_ctx->backends_subrs[i].ctx); | |||||
msg_debug_config ("closed backend %s", stat_ctx->backends_subrs[i].name); | |||||
} | } | ||||
} | } | ||||
guint i; | guint i; | ||||
for (i = 0; i < stat_ctx->classifiers_count; i ++) { | for (i = 0; i < stat_ctx->classifiers_count; i ++) { | ||||
if (strcmp (name, stat_ctx->classifiers[i].name) == 0) { | |||||
return &stat_ctx->classifiers[i]; | |||||
if (strcmp (name, stat_ctx->classifiers_subrs[i].name) == 0) { | |||||
return &stat_ctx->classifiers_subrs[i]; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
for (i = 0; i < stat_ctx->backends_count; i ++) { | for (i = 0; i < stat_ctx->backends_count; i ++) { | ||||
if (strcmp (name, stat_ctx->backends[i].name) == 0) { | |||||
return &stat_ctx->backends[i]; | |||||
if (strcmp (name, stat_ctx->backends_subrs[i].name) == 0) { | |||||
return &stat_ctx->backends_subrs[i]; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
for (i = 0; i < stat_ctx->tokenizers_count; i ++) { | for (i = 0; i < stat_ctx->tokenizers_count; i ++) { | ||||
if (strcmp (name, stat_ctx->tokenizers[i].name) == 0) { | |||||
return &stat_ctx->tokenizers[i]; | |||||
if (strcmp (name, stat_ctx->tokenizers_subrs[i].name) == 0) { | |||||
return &stat_ctx->tokenizers_subrs[i]; | |||||
} | |||||
} | |||||
return NULL; | |||||
} | |||||
struct rspamd_stat_cache * | |||||
rspamd_stat_get_cache (const gchar *name) | |||||
{ | |||||
guint i; | |||||
if (name == NULL || name[0] == '\0') { | |||||
name = RSPAMD_DEFAULT_CACHE; | |||||
} | |||||
for (i = 0; i < stat_ctx->caches_count; i++) { | |||||
if (strcmp (name, stat_ctx->caches_subrs[i].name) == 0) { | |||||
return &stat_ctx->caches_subrs[i]; | |||||
} | } | ||||
} | } | ||||
struct rspamd_stat_ctx { | struct rspamd_stat_ctx { | ||||
/* Subroutines for all objects */ | /* Subroutines for all objects */ | ||||
struct rspamd_stat_classifier *classifiers; | |||||
struct rspamd_stat_classifier *classifiers_subrs; | |||||
guint classifiers_count; | guint classifiers_count; | ||||
struct rspamd_stat_tokenizer *tokenizers; | |||||
struct rspamd_stat_tokenizer *tokenizers_subrs; | |||||
guint tokenizers_count; | guint tokenizers_count; | ||||
struct rspamd_stat_backend *backends; | |||||
struct rspamd_stat_backend *backends_subrs; | |||||
guint backends_count; | guint backends_count; | ||||
struct rspamd_stat_cache *caches; | |||||
struct rspamd_stat_cache *caches_subrs; | |||||
guint caches_count; | guint caches_count; | ||||
/* Runtime configuration */ | /* Runtime configuration */ | ||||
GPtrArray *statfiles; /* struct statfile */ | |||||
GPtrArray *statfiles; /* struct rspamd_statfile */ | |||||
GPtrArray *classifiers; /* struct rspamd_classifier */ | |||||
struct rspamd_config *cfg; | struct rspamd_config *cfg; | ||||
/* Global tokenizer */ | /* Global tokenizer */ | ||||
struct rspamd_stat_tokenizer *tokenizer; | struct rspamd_stat_tokenizer *tokenizer; | ||||
struct rspamd_stat_classifier * rspamd_stat_get_classifier (const gchar *name); | struct rspamd_stat_classifier * rspamd_stat_get_classifier (const gchar *name); | ||||
struct rspamd_stat_backend * rspamd_stat_get_backend (const gchar *name); | struct rspamd_stat_backend * rspamd_stat_get_backend (const gchar *name); | ||||
struct rspamd_stat_tokenizer * rspamd_stat_get_tokenizer (const gchar *name); | struct rspamd_stat_tokenizer * rspamd_stat_get_tokenizer (const gchar *name); | ||||
struct rspamd_stat_cache * rspamd_stat_get_cache (const gchar *name); | |||||
static GQuark rspamd_stat_quark (void) | static GQuark rspamd_stat_quark (void) | ||||
{ | { |