/* Defaults */
#define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "stat", fmt)
-#define FREQUENT_COUNT 1000 /* Size of frequent tables */
+#define FREQUENT_COUNT 5000 /* Size of frequent tables */
#define FREQUENT_PSAMPLE 100 /* Sampling rate, 1 in N */
/** @cond internal Fixed-size map of predefined metrics. */
struct stat_data {
map_t map;
struct {
- namehash_t *names;
- } frequent;
+ namehash_t *frequent;
+ namehash_t *expiring;
+ } queries;
};
/** @internal Subtract time (best effort) */
{
/* Sample key = {[2] type, [1-255] owner} */
char key[sizeof(uint16_t) + KNOT_DNAME_MAXLEN];
- /* Sample queries leading to iteration or expiring */
struct kr_query *qry = NULL;
WALK_LIST(qry, rplan->resolved) {
- if (!(qry->flags & QUERY_CACHED) || (qry->flags & QUERY_EXPIRING)) {
- int key_len = collect_key(key, qry->sname, qry->stype);
- unsigned *count = lru_set(data->frequent.names, key, key_len);
- if (count) {
+ /* Sample queries leading to iteration or expiring */
+ if ((qry->flags & QUERY_CACHED) && !(qry->flags & QUERY_EXPIRING)) {
+ continue;
+ }
+ int key_len = collect_key(key, qry->sname, qry->stype);
+ if (qry->flags & QUERY_EXPIRING) {
+ unsigned *count = lru_set(data->queries.expiring, key, key_len);
+ if (count)
+ *count += 1;
+ } else {
+ unsigned *count = lru_set(data->queries.frequent, key, key_len);
+ if (count)
*count += 1;
- }
}
}
}
}
/* Count cached and unresolved */
if (!EMPTY_LIST(rplan->resolved)) {
- struct kr_query *last = TAIL(rplan->resolved);
- if (last->flags & QUERY_CACHED) {
- stat_const_add(data, metric_answer_cached, 1);
- }
/* Histogram of answer latency. */
struct kr_query *first = HEAD(rplan->resolved);
+ struct kr_query *last = TAIL(rplan->resolved);
struct timeval now;
gettimeofday(&now, NULL);
float elapsed = time_diff(&first->timestamp, &now);
- if (elapsed < 10.0) {
+ if (last->flags & QUERY_CACHED) {
+ stat_const_add(data, metric_answer_cached, 1);
+ } else if (elapsed < 10.0) {
stat_const_add(data, metric_answer_10ms, 1);
} else if (elapsed < 100.0) {
stat_const_add(data, metric_answer_100ms, 1);
*
* Output: [{ count: <counter>, name: <qname>, type: <qtype>}, ... ]
*/
-static char* freq_list(void *env, struct kr_module *module, const char *args)
+static char* dump_list(void *env, struct kr_module *module, const char *args, namehash_t *table)
{
- struct stat_data *data = module->data;
- namehash_t *freq_table = data->frequent.names;
- if (!freq_table) {
+ if (!table) {
return NULL;
}
uint16_t key_type = 0;
char key_name[KNOT_DNAME_MAXLEN];
JsonNode *root = json_mkarray();
- for (unsigned i = 0; i < freq_table->size; ++i) {
- struct lru_slot *slot = lru_slot_at((struct lru_hash_base *)freq_table, i);
+ for (unsigned i = 0; i < table->size; ++i) {
+ struct lru_slot *slot = lru_slot_at((struct lru_hash_base *)table, i);
if (slot->key) {
/* Extract query name, type and counter */
memcpy(&key_type, slot->key, sizeof(key_type));
knot_dname_to_str(key_name, (uint8_t *)slot->key + sizeof(key_type), sizeof(key_name));
- unsigned *slot_val = lru_slot_val(slot, lru_slot_offset(freq_table));
+ unsigned *slot_val = lru_slot_val(slot, lru_slot_offset(table));
/* Convert to JSON object */
JsonNode *json_val = json_mkobject();
json_append_member(json_val, "count", json_mknumber(*slot_val));
return ret;
}
-static char* freq_turnover(void *env, struct kr_module *module, const char *args)
+static char* dump_frequent(void *env, struct kr_module *module, const char *args)
{
struct stat_data *data = module->data;
- namehash_t *freq_table = data->frequent.names;
- if (!freq_table) {
- return NULL;
- }
- JsonNode *root = json_mknumber(freq_table->evictions);
- char *ret = json_encode(root);
- json_delete(root);
- return ret;
+ return dump_list(env, module, args, data->queries.frequent);
}
-static char* freq_clear(void *env, struct kr_module *module, const char *args)
+static char* clear_frequent(void *env, struct kr_module *module, const char *args)
{
struct stat_data *data = module->data;
- namehash_t *freq_table = data->frequent.names;
- if (!freq_table) {
- return NULL;
- }
- lru_deinit(freq_table);
- lru_init(freq_table, FREQUENT_COUNT);
+ lru_deinit(data->queries.frequent);
+ lru_init(data->queries.frequent, FREQUENT_COUNT);
+ return NULL;
+}
+
+static char* dump_expiring(void *env, struct kr_module *module, const char *args)
+{
+ struct stat_data *data = module->data;
+ return dump_list(env, module, args, data->queries.expiring);
+}
+
+static char* clear_expiring(void *env, struct kr_module *module, const char *args)
+{
+ struct stat_data *data = module->data;
+ lru_deinit(data->queries.expiring);
+ lru_init(data->queries.expiring, FREQUENT_COUNT);
return NULL;
}
}
data->map = map_make();
module->data = data;
- data->frequent.names = malloc(lru_size(namehash_t, FREQUENT_COUNT));
- if (data->frequent.names) {
- lru_init(data->frequent.names, FREQUENT_COUNT);
+ data->queries.frequent = malloc(lru_size(namehash_t, FREQUENT_COUNT));
+ if (data->queries.frequent) {
+ lru_init(data->queries.frequent, FREQUENT_COUNT);
+ }
+ data->queries.expiring = malloc(lru_size(namehash_t, FREQUENT_COUNT));
+ if (data->queries.expiring) {
+ lru_init(data->queries.expiring, FREQUENT_COUNT);
}
return kr_ok();
}
struct stat_data *data = module->data;
if (data) {
map_clear(&data->map);
- lru_deinit(data->frequent.names);
- free(data->frequent.names);
+ lru_deinit(data->queries.frequent);
+ lru_deinit(data->queries.expiring);
+ free(data->queries.frequent);
+ free(data->queries.expiring);
free(data);
}
return kr_ok();
{ &stats_set, "set", "Set {key, val} metrics.", },
{ &stats_get, "get", "Get metrics for given key.", },
{ &stats_list, "list", "List observed metrics.", },
- { &freq_list, "queries", "List most frequent queries.", },
- { &freq_clear, "queries_clear", "Clear most frequent queries.", },
- { &freq_turnover, "queries_turnover", "Turnover of the frequent queries.", },
+ { &dump_frequent, "frequent", "List most frequent queries.", },
+ { &clear_frequent,"clear_frequent", "Clear frequent queries log.", },
+ { &dump_expiring, "expiring", "List expiring records.", },
+ { &clear_expiring,"clear_expiring", "Clear expiring records log.", },
{ NULL, NULL, NULL }
};
return prop_list;