// ---------------------------
// traversing
-void avl_walker(avl *node, void (*callback)(void *entry, void *data), void *data) {
- if(node->avl_link[0])
- avl_walker(node->avl_link[0], callback, data);
+int avl_walker(avl *node, int (*callback)(void *entry, void *data), void *data) {
+ int total = 0, ret = 0;
- callback(node, data);
+ if(node->avl_link[0]) {
+ ret = avl_walker(node->avl_link[0], callback, data);
+ if(ret < 0) return ret;
+ total += ret;
+ }
+
+ ret = callback(node, data);
+ if(ret < 0) return ret;
+ total += ret;
- if(node->avl_link[1])
- avl_walker(node->avl_link[1], callback, data);
+ if(node->avl_link[1]) {
+ ret = avl_walker(node->avl_link[1], callback, data);
+ if (ret < 0) return ret;
+ total += ret;
+ }
+
+ return total;
}
-void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data) {
- avl_walker(t->root, callback, data);
+int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data) {
+ return avl_walker(t->root, callback, data);
}
// ---------------------------
return ret;
}
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data) {
+int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data) {
+ int ret;
avl_read_lock(t);
- avl_traverse(&t->avl_tree, callback, data);
+ ret = avl_traverse(&t->avl_tree, callback, data);
avl_unlock(t);
+ return ret;
}
void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
void avl_init(avl_tree *t, int (*compar)(void *a, void *b));
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data);
-void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data);
+int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data);
+int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data);
#endif /* avl.h */
size_t counter;
};
-static void single_variable2json(void *entry, void *data) {
+static int single_variable2json(void *entry, void *data) {
struct variable2json_helper *helper = (struct variable2json_helper *)data;
RRDVAR *rv = (RRDVAR *)entry;
calculated_number value = rrdvar2number(rv);
buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
helper->counter++;
+
+ return 0;
}
void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
};
// callback for rendering PERSON_URLs
-static inline int registry_json_person_url_callback(void *entry, void *data) {
+static int registry_json_person_url_callback(void *entry, void *data) {
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
struct web_client *w = c->w;
buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->machine_name);
- return 1;
+ return 0;
}
// callback for rendering MACHINE_URLs
-static inline int registry_json_machine_url_callback(void *entry, void *data) {
+static int registry_json_machine_url_callback(void *entry, void *data) {
REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry;
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
struct web_client *w = c->w;
int count;
};
-int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
+static inline int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
REGISTRY_MACHINE *m = d->m;
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
- dictionary_get_all(p->person_urls, registry_json_person_url_callback, &c);
+ avl_traverse(&p->person_urls, registry_json_person_url_callback, &c);
buffer_strcat(w->response.data, "\n\t]\n");
registry_json_footer(w);
struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
// verify the old person has access to this machine
- dictionary_get_all(op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
+ avl_traverse(&op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
// verify the new person has access to this machine
data.count = 0;
- dictionary_get_all(np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
+ avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
if(!data.count) {
registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
registry_json_footer(w);
rrddim_set(stm, "persons", registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
rrddim_set(stm, "machines", registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
rrddim_set(stm, "urls", registry.urls_memory);
- rrddim_set(stm, "persons_urls", registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
+ rrddim_set(stm, "persons_urls", registry.persons_urls_memory);
rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
rrdset_done(stm);
}
// should only happen when netdata starts
extern int registry_init(void);
+/*
// free all data held by the registry
// should only happen when netdata exits
extern void registry_free(void);
+*/
// HTTP requests handled by the registry
extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
);
if(ret >= 0) {
- int ret2 = dictionary_get_all(p->person_urls, registry_person_save_url, fp);
+ //int ret2 = dictionary_get_all(p->person_urls, registry_person_save_url, fp);
+ int ret2 = avl_traverse(&p->person_urls, registry_person_save_url, fp);
if (ret2 < 0) return ret2;
ret += ret2;
}
return 0;
}
-
+/*
void registry_free(void) {
if(!registry.enabled) return;
debug(D_REGISTRY, "Registry: destroying machines dictionary");
dictionary_destroy(registry.machines);
}
+*/
}
if(pp) *pp = p;
- REGISTRY_PERSON_URL *pu = dictionary_get(p->person_urls, url);
+ REGISTRY_PERSON_URL *pu = registry_person_url_find(p, url);
if(!pu) {
info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
return NULL;
return NULL;
}
- REGISTRY_PERSON_URL *dpu = dictionary_get(p->person_urls, delete_url);
+ REGISTRY_PERSON_URL *dpu = registry_person_url_find(p, delete_url);
if(!dpu) {
info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
return NULL;
registry_log('D', p, m, pu->url, dpu->url->url);
- dictionary_del(p->person_urls, dpu->url->url);
+ registry_person_url_del(p, dpu);
registry_url_unlink(dpu->url);
struct machine_request_callback_data rdata = { m, NULL };
// request a walk through on the dictionary
- // no need for locking here, the underlying dictionary has its own
- dictionary_get_all(p->person_urls, machine_request_callback, &rdata);
+ avl_traverse(&p->person_urls, machine_request_callback, &rdata);
if(rdata.result)
return m;
if(likely(m->last_t < (uint32_t)when)) m->last_t = (uint32_t)when;
if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
- info("registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url);
+ debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url);
mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
}
#include "registry_internals.h"
// ----------------------------------------------------------------------------
-// PERSON
+// PERSON_URL
-REGISTRY_PERSON *registry_person_find(const char *person_guid) {
- debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
- return dictionary_get(registry.persons, person_guid);
+int person_url_compare(void *a, void *b) {
+ register uint32_t hash1 = ((REGISTRY_PERSON_URL *)a)->url->hash;
+ register uint32_t hash2 = ((REGISTRY_PERSON_URL *)b)->url->hash;
+
+ if(hash1 < hash2) return -1;
+ else if(hash1 > hash2) return 1;
+ else return strcmp(((REGISTRY_PERSON_URL *)a)->url->url, ((REGISTRY_PERSON_URL *)b)->url->url);
+}
+
+#define registry_person_url_index_add(person, rc) (REGISTRY_PERSON_URL *)avl_insert(&((person)->person_urls), (avl *)(rc))
+#define registry_person_url_index_del(person, rc) (REGISTRY_PERSON_URL *)avl_remove(&((person)->person_urls), (avl *)(rc))
+
+REGISTRY_PERSON_URL *registry_person_url_find(REGISTRY_PERSON *p, const char *url) {
+ debug(D_REGISTRY, "Registry: registry_person_url_find('%s', '%s')", p->guid, url);
+
+ char buf[sizeof(REGISTRY_URL) + strlen(url)];
+
+ REGISTRY_URL *u = (REGISTRY_URL *)&buf;
+ strcpy(u->url, url);
+ u->hash = simple_hash(u->url);
+
+ REGISTRY_PERSON_URL tpu = { .url = u };
+
+ REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu);
+ return pu;
}
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
+ debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
+
// protection from too big names
if(namelen > registry.max_name_length)
namelen = registry.max_name_length;
- debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
- sizeof(REGISTRY_PERSON_URL) + namelen);
-
REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen);
// a simple strcpy() should do the job
registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen;
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
- dictionary_set(p->person_urls, u->url, pu, sizeof(REGISTRY_PERSON_URL));
+ registry_person_url_index_add(p, pu);
+
registry_url_link(u);
return pu;
}
+// this function is needed to change the name of a PERSON_URL
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu) {
- // this function is needed to change the name of a PERSON_URL
+ debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
- debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
- sizeof(REGISTRY_PERSON_URL) + namelen);
+ // remove the existing one from the index
+ registry_person_url_index_del(p, pu);
+ registry_url_unlink(pu->url);
+ pu->machine->links--;
+ registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(pu->machine_name);
+ // allocate a new one
REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
tpu->first_t = pu->first_t;
tpu->last_t = pu->last_t;
tpu->usages = pu->usages;
-
- // ok, these are a hack - since the registry_person_url_allocate() is
- // adding these, we have to subtract them
- tpu->machine->links--;
- registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(pu->machine_name);
- registry_url_unlink(u);
+ tpu->flags = pu->flags;
freez(pu);
-
return tpu;
}
-REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
- REGISTRY_PERSON *p = NULL;
- debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
+void registry_person_url_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
+ debug(D_REGISTRY, "Registry: registry_person_url_del('%s', '%s')", p->guid, pu->url->url);
+ registry_person_url_index_del(p, pu);
+}
- p = mallocz(sizeof(REGISTRY_PERSON));
+// ----------------------------------------------------------------------------
+// PERSON
+REGISTRY_PERSON *registry_person_find(const char *person_guid) {
+ debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
+ return dictionary_get(registry.persons, person_guid);
+}
+
+REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
+ debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
+
+ REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON));
if(!person_guid) {
- for (; ;) {
+ for(;;) {
uuid_t uuid;
uuid_generate(uuid);
uuid_unparse_lower(uuid, p->guid);
strncpyz(p->guid, person_guid, GUID_LEN);
debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
- p->person_urls = dictionary_create(DICTIONARY_FLAGS);
+ avl_init(&p->person_urls, person_url_compare);
p->first_t = p->last_t = (uint32_t)when;
p->usages = 0;
// 3. if it is not valid, create a new one
// 4. return it
REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
+ debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid);
+
REGISTRY_PERSON *p = NULL;
if(person_guid && *person_guid) {
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
- REGISTRY_PERSON_URL *pu = dictionary_get(p->person_urls, u->url);
+ REGISTRY_PERSON_URL *pu = registry_person_url_find(p, u->url);
if(!pu) {
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
pu = registry_person_url_allocate(p, m, u, name, namelen, when);
if(pu->machine != m) {
REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url);
if(mu) {
- info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
p->guid, m->guid, u->url, pu->machine->guid);
mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
}
else {
- info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
p->guid, m->guid, u->url, pu->machine->guid);
}
if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when;
if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
- info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
}
// for each PERSON-URL pair we keep this
struct registry_person_url {
+ avl avl; // binary tree node
+
REGISTRY_URL *url; // de-duplicated URL
REGISTRY_MACHINE *machine; // link the MACHINE of this URL
struct registry_person {
char guid[GUID_LEN + 1]; // the person GUID
- DICTIONARY *person_urls; // dictionary of PERSON_URL *
+ avl_tree person_urls; // dictionary of PERSON_URLs
uint32_t first_t; // the first time we saw this
uint32_t last_t; // the last time we saw this
uint32_t usages; // how many times this has been accessed
+
+ //uint32_t flags;
+ //char *email;
};
typedef struct registry_person REGISTRY_PERSON;
extern REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when);
extern REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when);
+extern REGISTRY_PERSON_URL *registry_person_url_find(REGISTRY_PERSON *p, const char *url);
+extern void registry_person_url_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu);
+
#endif //NETDATA_REGISTRY_PERSON_H