/* This file is part of varnish-mib
Copyright (C) 2018 Sergey Poznyakoff
Varnish-mib is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Varnish-mib is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with varnish-mib. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "backend.h"
static size_t hash_size[] = {
7, 17, 37, 101, 229, 487, 1009, 2039, 4091, 8191, 16411
};
static size_t hash_num = 0;
static struct VSC_point **dict;
#define SIZE_T_MAX ((size_t)-1)
static inline size_t
rotl(size_t x, int n)
{
return ((x << n) | (x >> ((CHAR_BIT * sizeof x) - n))) & SIZE_T_MAX;
}
static size_t
hash(const char *str)
{
size_t value = 0;
unsigned char ch;
while ((ch = *str++))
value = ch + rotl(value, 7);
return value % hash_size[hash_num];
}
struct VSC_point **lookup(const char *name, int install);
static void
rehash(void)
{
struct VSC_point **old_dict = dict;
size_t old_size = hash_size[hash_num];
size_t i;
++hash_num;
AN(hash_num < sizeof(hash_size) / sizeof(hash_size[0]));
dict = calloc(hash_size[hash_num], sizeof(dict[0]));
AN(dict);
for (i = 0; i < old_size; i++) {
if (old_dict[i])
*lookup(old_dict[i]->name, 1) = old_dict[i];
}
free(old_dict);
}
struct VSC_point **
lookup(const char *name, int install)
{
size_t i, pos;
if (!dict) {
if (install) {
dict = calloc(hash_size[hash_num], sizeof(dict[0]));
AN(dict);
} else
return NULL;
}
pos = hash(name);
for (i = pos; dict[i];) {
if (strcmp(dict[i]->name, name) == 0) {
return &dict[i];
}
if (++i >= hash_size[hash_num])
i = 0;
if (i == pos)
break;
}
if (!install)
return NULL;
if (!dict[i])
return &dict[i];
rehash();
return lookup(name, install);
}
int
dict_lookup(char const *key, uint64_t *val)
{
struct VSC_point **ent;
ent = lookup(key, 0);
if (!ent) {
fprintf(stderr, "%s NOT FOUND\n", key);
}
if (!ent)
return -1;
*val = *(uint64_t*)(*ent)->ptr;
return 0;
}
void
dict_clear(void)
{
if (dict) {
size_t i;
for (i = 0; i < hash_size[hash_num]; i++)
if (dict[i])
VSC_Destroy_Point(&dict[i]);
}
}
struct VSC_point const *
dict_install(struct VSC_point const *pt)
{
struct VSC_point **ent;
ent = lookup(pt->name, 1);
AN(ent);
if (*ent)
VSC_Destroy_Point(ent);
*ent = VSC_Clone_Point(pt);
return *ent;
}
static int
load_cb(void *priv, const struct VSC_point *vpt)
{
AZ(strcmp(vpt->ctype, "uint64_t"));
vpt = dict_install(vpt);
if (strncmp(vpt->name, "VBE.", 4) == 0) {
char const *name = vpt->name + 4;
char *p = strrchr(name, '.');
if (p) {
backend_register(name, p - name, p + 1, vpt);
}
}
return 0;
}
void
dict_load(struct vsc *vsc)
{
struct vsm_fantom fantom = VSM_FANTOM_NULL;
dict_clear();
backend_clear();
VSC_Iter(vsc, &fantom, load_cb, NULL);
backend_collect_addr();
}