// SPDX-License-Identifier: GPL-3.0-or-later
#include "internal.h"
#include "aclk/aclk_capas.h"
// ----------------------------------------------------------------------------
// /api/v2/contexts API
typedef enum __attribute__ ((__packed__)) {
FTS_MATCHED_NONE = 0,
FTS_MATCHED_HOST,
FTS_MATCHED_CONTEXT,
FTS_MATCHED_INSTANCE,
FTS_MATCHED_DIMENSION,
FTS_MATCHED_LABEL,
FTS_MATCHED_ALERT,
FTS_MATCHED_ALERT_INFO,
FTS_MATCHED_FAMILY,
FTS_MATCHED_TITLE,
FTS_MATCHED_UNITS,
} FTS_MATCH;
static const char *fts_match_to_string(FTS_MATCH match) {
switch(match) {
case FTS_MATCHED_HOST:
return "HOST";
case FTS_MATCHED_CONTEXT:
return "CONTEXT";
case FTS_MATCHED_INSTANCE:
return "INSTANCE";
case FTS_MATCHED_DIMENSION:
return "DIMENSION";
case FTS_MATCHED_ALERT:
return "ALERT";
case FTS_MATCHED_ALERT_INFO:
return "ALERT_INFO";
case FTS_MATCHED_LABEL:
return "LABEL";
case FTS_MATCHED_FAMILY:
return "FAMILY";
case FTS_MATCHED_TITLE:
return "TITLE";
case FTS_MATCHED_UNITS:
return "UNITS";
default:
return "NONE";
}
}
struct rrdcontext_to_json_v2_entry {
size_t count;
STRING *id;
STRING *family;
uint32_t priority;
time_t first_time_s;
time_t last_time_s;
RRD_FLAGS flags;
FTS_MATCH match;
};
typedef struct full_text_search_index {
size_t searches;
size_t string_searches;
size_t char_searches;
} FTS_INDEX;
static inline bool full_text_search_string(FTS_INDEX *fts, SIMPLE_PATTERN *q, STRING *ptr) {
fts->searches++;
fts->string_searches++;
return simple_pattern_matches_string(q, ptr);
}
static inline bool full_text_search_char(FTS_INDEX *fts, SIMPLE_PATTERN *q, char *ptr) {
fts->searches++;
fts->char_searches++;
return simple_pattern_matches(q, ptr);
}
struct rrdcontext_to_json_v2_data {
time_t now;
BUFFER *wb;
struct api_v2_contexts_request *request;
DICTIONARY *ctx;
CONTEXTS_V2_OPTIONS options;
struct query_versions versions;
struct {
SIMPLE_PATTERN *scope_pattern;
SIMPLE_PATTERN *pattern;
size_t ni;
} nodes;
struct {
SIMPLE_PATTERN *scope_pattern;
SIMPLE_PATTERN *pattern;
} contexts;
struct {
FTS_MATCH host_match;
char host_node_id_str[UUID_STR_LEN];
SIMPLE_PATTERN *pattern;
FTS_INDEX fts;
} q;
struct {
bool enabled;
bool relative;
time_t after;
time_t before;
} window;
struct query_timings timings;
};
static FTS_MATCH rrdcontext_to_json_v2_full_text_search(struct rrdcontext_to_json_v2_data *ctl, RRDCONTEXT *rc, SIMPLE_PATTERN *q) {
if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->id) ||
full_text_search_string(&ctl->q.fts, q, rc->family)))
return FTS_MATCHED_CONTEXT;
if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->title)))
return FTS_MATCHED_TITLE;
if(unlikely(full_text_search_string(&ctl->q.fts, q, rc->units)))
return FTS_MATCHED_UNITS;
FTS_MATCH matched = FTS_MATCHED_NONE;
RRDINSTANCE *ri;
dfe_start_read(rc->rrdinstances, ri) {
if(matched) break;
if(ctl->window.enabled && !query_matches_retention(ctl->window.after, ctl->window.before, ri->first_time_s, ri->last_time_s, 0))
continue;
if(unlikely(full_text_search_string(&ctl->q.fts, q, ri->id)) ||
(ri->name != ri->id && full_text_search_string(&ctl->q.fts, q, ri->name))) {
matched = FTS_MATCHED_INSTANCE;
break;
}
RRDMETRIC *rm;
dfe_start_read(ri->rrdmetrics, rm) {
if(ctl->window.enabled