X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=blobdiff_plain;f=src%2Fcore%2Fplugin.c;h=ecd84b5f9c5f5f525017872ecdf54fe234a6267f;hp=76b0b1e45b656a6416bb8aa526581cd311ac5921;hb=55f6919736b7574b8fb905eced926d8c003411c6;hpb=5cf58d25c37585bdc7aef79cfc899fdf5ba02ef2 diff --git a/src/core/plugin.c b/src/core/plugin.c index 76b0b1e..ecd84b5 100644 --- a/src/core/plugin.c +++ b/src/core/plugin.c @@ -114,6 +114,14 @@ typedef struct { } reader_t; #define READER(obj) ((reader_t *)(obj)) +typedef struct { + callback_t super; /* cb_callback will always be NULL */ +#define ts_user_data super.cb_user_data +#define ts_ctx super.cb_ctx + sdb_timeseries_fetcher_t impl; +} ts_fetcher_t; +#define TS_FETCHER(obj) ((ts_fetcher_t *)(obj)) + /* * private variables */ @@ -133,7 +141,7 @@ static sdb_llist_t *collector_list = NULL; static sdb_llist_t *cname_list = NULL; static sdb_llist_t *shutdown_list = NULL; static sdb_llist_t *log_list = NULL; -static sdb_llist_t *ts_fetcher_list = NULL; +static sdb_llist_t *timeseries_fetcher_list = NULL; static sdb_llist_t *writer_list = NULL; static sdb_llist_t *reader_list = NULL; @@ -147,7 +155,7 @@ static struct { { "cname", &cname_list }, { "shutdown", &shutdown_list }, { "log", &log_list }, - { "timeseries fetcher", &ts_fetcher_list }, + { "timeseries fetcher", ×eries_fetcher_list }, { "store writer", &writer_list }, { "store reader", &reader_list }, }; @@ -259,6 +267,73 @@ plugin_unregister_by_name(const char *plugin_name) /* else: other callbacks still reference it */ } /* plugin_unregister_by_name */ +/* + * store writer wrapper for performing database queries: + * It wraps another store writer, adding extra logic as needed. + */ + +typedef struct { + sdb_object_t super; + sdb_store_writer_t *w; + sdb_object_t *ud; +} query_writer_t; +#define QUERY_WRITER_INIT(w, ud) { SDB_OBJECT_INIT, (w), (ud) } +#define QUERY_WRITER(obj) ((query_writer_t *)(obj)) + +static int +query_store_host(sdb_store_host_t *host, sdb_object_t *user_data) +{ + query_writer_t *qw = QUERY_WRITER(user_data); + return qw->w->store_host(host, qw->ud); +} /* query_store_host */ + +static int +query_store_service(sdb_store_service_t *service, sdb_object_t *user_data) +{ + query_writer_t *qw = QUERY_WRITER(user_data); + return qw->w->store_service(service, qw->ud); +} /* query_store_service */ + +static int +query_store_metric(sdb_store_metric_t *metric, sdb_object_t *user_data) +{ + query_writer_t *qw = QUERY_WRITER(user_data); + sdb_timeseries_info_t *infos[metric->stores_num]; + sdb_metric_store_t stores[metric->stores_num]; + + const sdb_metric_store_t *orig_stores = metric->stores; + int status; + size_t i; + + for (i = 0; i < metric->stores_num; i++) { + /* TODO: Make this optional using query options. */ + sdb_metric_store_t *s = stores + i; + *s = metric->stores[i]; + infos[i] = sdb_plugin_describe_timeseries(s->type, s->id); + s->info = infos[i]; + } + + metric->stores = stores; + status = qw->w->store_metric(metric, qw->ud); + metric->stores = orig_stores; + + for (i = 0; i < metric->stores_num; i++) + sdb_timeseries_info_destroy(infos[i]); + return status; +} /* query_store_metric */ + +static int +query_store_attribute(sdb_store_attribute_t *attr, sdb_object_t *user_data) +{ + query_writer_t *qw = QUERY_WRITER(user_data); + return qw->w->store_attribute(attr, qw->ud); +} /* query_store_attribute */ + +static sdb_store_writer_t query_writer = { + query_store_host, query_store_service, + query_store_metric, query_store_attribute, +}; + /* * private types */ @@ -345,24 +420,39 @@ ctx_create(const char *name) return ctx; } /* ctx_create */ -static int -plugin_cb_init(sdb_object_t *obj, va_list ap) +/* + * plugin_init_ok: + * Checks whether the registration of a new plugin identified by 'obj' is + * okay. It consumes the first two arguments of 'ap'. + */ +static bool +plugin_init_ok(sdb_object_t *obj, va_list ap) { sdb_llist_t **list = va_arg(ap, sdb_llist_t **); - const char *type = va_arg(ap, const char *); - void *callback = va_arg(ap, void *); - sdb_object_t *ud = va_arg(ap, sdb_object_t *); + const char *type = va_arg(ap, const char *); - assert(list); - assert(type); - assert(obj); + assert(list); assert(type); if (sdb_llist_search_by_name(*list, obj->name)) { sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' " "has already been registered. Ignoring newly " "registered version.", type, obj->name); - return -1; + return 0; } + return 1; +} /* plugin_init_ok */ + +static int +plugin_cb_init(sdb_object_t *obj, va_list ap) +{ + void *callback; + sdb_object_t *ud; + + if (! plugin_init_ok(obj, ap)) + return -1; + + callback = va_arg(ap, void *); + ud = va_arg(ap, sdb_object_t *); /* cb_ctx may be NULL if the plugin was not registered by a plugin */ @@ -400,9 +490,14 @@ static sdb_type_t collector_type = { static int plugin_writer_init(sdb_object_t *obj, va_list ap) { - sdb_store_writer_t *impl = va_arg(ap, sdb_store_writer_t *); - sdb_object_t *ud = va_arg(ap, sdb_object_t *); + sdb_store_writer_t *impl; + sdb_object_t *ud; + if (! plugin_init_ok(obj, ap)) + return -1; + + impl = va_arg(ap, sdb_store_writer_t *); + ud = va_arg(ap, sdb_object_t *); assert(impl); if ((! impl->store_host) || (! impl->store_service) @@ -412,12 +507,6 @@ plugin_writer_init(sdb_object_t *obj, va_list ap) obj->name); return -1; } - if (sdb_llist_search_by_name(writer_list, obj->name)) { - sdb_log(SDB_LOG_WARNING, "core: store writer callback '%s' " - "has already been registered. Ignoring newly " - "registered version.", obj->name); - return -1; - } /* ctx may be NULL if the callback was not registered by a plugin */ @@ -448,9 +537,14 @@ static sdb_type_t writer_type = { static int plugin_reader_init(sdb_object_t *obj, va_list ap) { - sdb_store_reader_t *impl = va_arg(ap, sdb_store_reader_t *); - sdb_object_t *ud = va_arg(ap, sdb_object_t *); + sdb_store_reader_t *impl; + sdb_object_t *ud; + + if (! plugin_init_ok(obj, ap)) + return -1; + impl = va_arg(ap, sdb_store_reader_t *); + ud = va_arg(ap, sdb_object_t *); assert(impl); if ((! impl->prepare_query) || (! impl->execute_query)) { @@ -459,12 +553,6 @@ plugin_reader_init(sdb_object_t *obj, va_list ap) obj->name); return -1; } - if (sdb_llist_search_by_name(reader_list, obj->name)) { - sdb_log(SDB_LOG_WARNING, "core: store reader callback '%s' " - "has already been registered. Ignoring newly " - "registered version.", obj->name); - return -1; - } /* ctx may be NULL if the callback was not registered by a plugin */ @@ -492,6 +580,52 @@ static sdb_type_t reader_type = { plugin_reader_destroy }; +static int +plugin_ts_fetcher_init(sdb_object_t *obj, va_list ap) +{ + sdb_timeseries_fetcher_t *impl; + sdb_object_t *ud; + + if (! plugin_init_ok(obj, ap)) + return -1; + + impl = va_arg(ap, sdb_timeseries_fetcher_t *); + ud = va_arg(ap, sdb_object_t *); + assert(impl); + + if ((! impl->describe) || (! impl->fetch)) { + sdb_log(SDB_LOG_ERR, "core: timeseries fetcher callback '%s' " + "does not fully implement the interface.", + obj->name); + return -1; + } + + /* ctx may be NULL if the callback was not registered by a plugin */ + + TS_FETCHER(obj)->impl = *impl; + TS_FETCHER(obj)->ts_ctx = ctx_get(); + sdb_object_ref(SDB_OBJ(TS_FETCHER(obj)->ts_ctx)); + + sdb_object_ref(ud); + TS_FETCHER(obj)->ts_user_data = ud; + return 0; +} /* plugin_ts_fetcher_init */ + +static void +plugin_ts_fetcher_destroy(sdb_object_t *obj) +{ + assert(obj); + sdb_object_deref(TS_FETCHER(obj)->ts_user_data); + sdb_object_deref(SDB_OBJ(TS_FETCHER(obj)->ts_ctx)); +} /* plugin_ts_fetcher_destroy */ + +static sdb_type_t ts_fetcher_type = { + sizeof(ts_fetcher_t), + + plugin_ts_fetcher_init, + plugin_ts_fetcher_destroy +}; + static int module_init(const char *name, lt_dlhandle lh, sdb_plugin_info_t *info) { @@ -628,12 +762,12 @@ plugin_get_name(const char *name, char *buf, size_t bufsize) } /* plugin_get_name */ static int -plugin_add_callback(sdb_llist_t **list, const char *type, - const char *name, void *callback, sdb_object_t *user_data) +plugin_add_impl(sdb_llist_t **list, sdb_type_t T, const char *type, + const char *name, void *impl, sdb_object_t *user_data) { sdb_object_t *obj; - if ((! name) || (! callback)) + if ((! name) || (! impl)) return -1; assert(list); @@ -643,8 +777,7 @@ plugin_add_callback(sdb_llist_t **list, const char *type, if (! *list) return -1; - obj = sdb_object_create(name, callback_type, - list, type, callback, user_data); + obj = sdb_object_create(name, T, list, type, impl, user_data); if (! obj) return -1; @@ -659,7 +792,7 @@ plugin_add_callback(sdb_llist_t **list, const char *type, sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.", type, name); return 0; -} /* plugin_add_callback */ +} /* plugin_add_impl */ /* * object meta-data @@ -896,8 +1029,8 @@ sdb_plugin_register_config(sdb_plugin_config_cb callback) "config callback from outside a plugin"); return -1; } - return plugin_add_callback(&config_list, "config", ctx->info.plugin_name, - (void *)callback, NULL); + return plugin_add_impl(&config_list, callback_type, "config", + ctx->info.plugin_name, (void *)callback, NULL); } /* sdb_plugin_register_config */ int @@ -905,7 +1038,7 @@ sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback, sdb_object_t *user_data) { char cb_name[1024]; - return plugin_add_callback(&init_list, "init", + return plugin_add_impl(&init_list, callback_type, "init", plugin_get_name(name, cb_name, sizeof(cb_name)), (void *)callback, user_data); } /* sdb_plugin_register_init */ @@ -915,7 +1048,7 @@ sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback, sdb_object_t *user_data) { char cb_name[1024]; - return plugin_add_callback(&shutdown_list, "shutdown", + return plugin_add_impl(&shutdown_list, callback_type, "shutdown", plugin_get_name(name, cb_name, sizeof(cb_name)), (void *)callback, user_data); } /* sdb_plugin_register_shutdown */ @@ -925,7 +1058,7 @@ sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback, sdb_object_t *user_data) { char cb_name[1024]; - return plugin_add_callback(&log_list, "log", + return plugin_add_impl(&log_list, callback_type, "log", plugin_get_name(name, cb_name, sizeof(cb_name)), callback, user_data); } /* sdb_plugin_register_log */ @@ -935,7 +1068,7 @@ sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback, sdb_object_t *user_data) { char cb_name[1024]; - return plugin_add_callback(&cname_list, "cname", + return plugin_add_impl(&cname_list, callback_type, "cname", plugin_get_name(name, cb_name, sizeof(cb_name)), callback, user_data); } /* sdb_plugin_register_cname */ @@ -1001,46 +1134,21 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback } /* sdb_plugin_register_collector */ int -sdb_plugin_register_ts_fetcher(const char *name, - sdb_plugin_fetch_ts_cb callback, sdb_object_t *user_data) +sdb_plugin_register_timeseries_fetcher(const char *name, + sdb_timeseries_fetcher_t *fetcher, sdb_object_t *user_data) { - return plugin_add_callback(&ts_fetcher_list, "time-series fetcher", - name, callback, user_data); -} /* sdb_plugin_register_ts_fetcher */ + return plugin_add_impl(×eries_fetcher_list, ts_fetcher_type, "time-series fetcher", + name, fetcher, user_data); +} /* sdb_plugin_register_timeseries_fetcher */ int sdb_plugin_register_writer(const char *name, sdb_store_writer_t *writer, sdb_object_t *user_data) { char cb_name[1024]; - sdb_object_t *obj; - - if ((! name) || (! writer)) - return -1; - - if (! writer_list) - writer_list = sdb_llist_create(); - if (! writer_list) - return -1; - - plugin_get_name(name, cb_name, sizeof(cb_name)); - - obj = sdb_object_create(cb_name, writer_type, + return plugin_add_impl(&writer_list, writer_type, "store writer", + plugin_get_name(name, cb_name, sizeof(cb_name)), writer, user_data); - if (! obj) - return -1; - - if (sdb_llist_append(writer_list, obj)) { - sdb_object_deref(obj); - return -1; - } - - /* pass control to the list */ - sdb_object_deref(obj); - - sdb_log(SDB_LOG_INFO, "core: Registered store writer callback '%s'.", - cb_name); - return 0; } /* sdb_store_register_writer */ int @@ -1048,34 +1156,9 @@ sdb_plugin_register_reader(const char *name, sdb_store_reader_t *reader, sdb_object_t *user_data) { char cb_name[1024]; - sdb_object_t *obj; - - if ((! name) || (! reader)) - return -1; - - if (! reader_list) - reader_list = sdb_llist_create(); - if (! reader_list) - return -1; - - plugin_get_name(name, cb_name, sizeof(cb_name)); - - obj = sdb_object_create(cb_name, reader_type, + return plugin_add_impl(&reader_list, reader_type, "store reader", + plugin_get_name(name, cb_name, sizeof(cb_name)), reader, user_data); - if (! obj) - return -1; - - if (sdb_llist_append(reader_list, obj)) { - sdb_object_deref(obj); - return -1; - } - - /* pass control to the list */ - sdb_object_deref(obj); - - sdb_log(SDB_LOG_INFO, "core: Registered store reader callback '%s'.", - cb_name); - return 0; } /* sdb_plugin_register_reader */ void @@ -1517,8 +1600,7 @@ sdb_timeseries_t * sdb_plugin_fetch_timeseries(const char *type, const char *id, sdb_timeseries_opts_t *opts) { - callback_t *plugin; - sdb_plugin_fetch_ts_cb callback; + ts_fetcher_t *fetcher; sdb_timeseries_t *ts; ctx_t *old_ctx; @@ -1526,28 +1608,54 @@ sdb_plugin_fetch_timeseries(const char *type, const char *id, if ((! type) || (! id) || (! opts)) return NULL; - plugin = CB(sdb_llist_search_by_name(ts_fetcher_list, type)); - if (! plugin) { + fetcher = TS_FETCHER(sdb_llist_search_by_name(timeseries_fetcher_list, type)); + if (! fetcher) { sdb_log(SDB_LOG_ERR, "core: Cannot fetch time-series of type %s: " "no such plugin loaded", type); errno = ENOENT; return NULL; } - old_ctx = ctx_set(plugin->cb_ctx); - callback = (sdb_plugin_fetch_ts_cb)plugin->cb_callback; - ts = callback(id, opts, plugin->cb_user_data); + old_ctx = ctx_set(fetcher->ts_ctx); + ts = fetcher->impl.fetch(id, opts, fetcher->ts_user_data); ctx_set(old_ctx); return ts; } /* sdb_plugin_fetch_timeseries */ +sdb_timeseries_info_t * +sdb_plugin_describe_timeseries(const char *type, const char *id) +{ + ts_fetcher_t *fetcher; + sdb_timeseries_info_t *ts_info; + + ctx_t *old_ctx; + + if ((! type) || (! id)) + return NULL; + + fetcher = TS_FETCHER(sdb_llist_search_by_name(timeseries_fetcher_list, type)); + if (! fetcher) { + sdb_log(SDB_LOG_ERR, "core: Cannot describe time-series of type %s: " + "no such plugin loaded", type); + errno = ENOENT; + return NULL; + } + + old_ctx = ctx_set(fetcher->ts_ctx); + ts_info = fetcher->impl.describe(id, fetcher->ts_user_data); + ctx_set(old_ctx); + return ts_info; +} /* sdb_plugin_describe_timeseries */ + int sdb_plugin_query(sdb_ast_node_t *ast, sdb_store_writer_t *w, sdb_object_t *wd, sdb_strbuf_t *errbuf) { - size_t n = sdb_llist_len(reader_list); + query_writer_t qw = QUERY_WRITER_INIT(w, wd); reader_t *reader; sdb_object_t *q; + + size_t n = sdb_llist_len(reader_list); int status = 0; if (! ast) @@ -1577,7 +1685,7 @@ sdb_plugin_query(sdb_ast_node_t *ast, q = reader->impl.prepare_query(ast, errbuf, reader->r_user_data); if (q) - status = reader->impl.execute_query(q, w, SDB_OBJ(wd), + status = reader->impl.execute_query(q, &query_writer, SDB_OBJ(&qw), errbuf, reader->r_user_data); else status = -1; @@ -1733,8 +1841,10 @@ sdb_plugin_store_metric(const char *hostname, const char *name, metric.hostname = cname; metric.name = name; if (store) { - metric.store.type = store->type; - metric.store.id = store->id; + if (store->last_update < last_update) + store->last_update = last_update; + metric.stores = store; + metric.stores_num = 1; } metric.last_update = last_update ? last_update : sdb_gettime(); if (get_interval(SDB_METRIC, cname, -1, NULL, name,