summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2016-12-31 21:08:24 +0200
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2016-12-31 21:08:24 +0200
commitba97a9f4d4dd21b74af45e511470bcbbc60ad992 (patch)
tree69338fa8da88af62670873229aae35b5d7e56aea
parent97da3cf73b6e55e4f33282db75e0503c90f21399 (diff)
removed over-optimization at the registry to simplify its logic and remove race conditions that could result to crashes; registry is now split into multiple files, to allow easier enhancements
-rwxr-xr-xCMakeLists.txt9
-rw-r--r--src/Makefile.am7
-rw-r--r--src/common.h10
-rw-r--r--src/registry.c1715
-rw-r--r--src/registry.h66
-rw-r--r--src/registry_db.c342
-rw-r--r--src/registry_init.c160
-rw-r--r--src/registry_internals.c317
-rw-r--r--src/registry_internals.h92
-rw-r--r--src/registry_log.c133
-rw-r--r--src/registry_machine.c101
-rw-r--r--src/registry_machine.h41
-rw-r--r--src/registry_person.c175
-rw-r--r--src/registry_person.h44
-rw-r--r--src/registry_url.c74
-rw-r--r--src/registry_url.h28
-rw-r--r--src/web_client.c58
17 files changed, 1692 insertions, 1680 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb56d2a0c9..47faf76b86 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,7 +94,14 @@ set(NETDATA_SOURCE_FILES
src/web_client.h
src/web_server.c
src/web_server.h
- src/socket.c src/socket.h)
+ src/socket.c src/socket.h
+ src/registry_url.c
+ src/registry_url.h
+ src/registry_internals.h
+ src/registry_person.c
+ src/registry_person.h
+ src/registry_machine.c
+ src/registry_machine.h src/registry_internals.c src/registry_init.c src/registry_db.c src/registry_log.c)
set(APPS_PLUGIN_SOURCE_FILES
src/appconfig.c
diff --git a/src/Makefile.am b/src/Makefile.am
index e1f87b5e4d..6ceeecde71 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,6 +50,13 @@ netdata_SOURCES = \
procfile.c procfile.h \
proc_self_mountinfo.c proc_self_mountinfo.h \
registry.c registry.h \
+ registry_internals.c registry_internals.h \
+ registry_url.c registry_url.h \
+ registry_person.c registry_person.h \
+ registry_machine.c registry_machine.h \
+ registry_init.c \
+ registry_db.c \
+ registry_log.c \
rrd.c rrd.h \
rrd2json.c rrd2json.h \
storage_number.c storage_number.h \
diff --git a/src/common.h b/src/common.h
index baa95dcb07..0fc4e820dc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -170,6 +170,8 @@
#endif
#define abs(x) ((x < 0)? -x : x)
+#define GUID_LEN 36
+
extern void netdata_fix_chart_id(char *s);
extern void netdata_fix_chart_name(char *s);
@@ -198,10 +200,10 @@ extern void *mallocz_int(const char *file, const char *function, const unsigned
extern void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size);
extern void freez_int(const char *file, const char *function, const unsigned long line, void *ptr);
#else
-extern char *strdupz(const char *s);
-extern void *callocz(size_t nmemb, size_t size);
-extern void *mallocz(size_t size);
-extern void *reallocz(void *ptr, size_t size);
+extern char *strdupz(const char *s) __attribute__((returns_nonnull));
+extern void *callocz(size_t nmemb, size_t size) __attribute__((returns_nonnull));
+extern void *mallocz(size_t size) __attribute__((returns_nonnull));
+extern void *reallocz(void *ptr, size_t size) __attribute__((returns_nonnull));
extern void freez(void *ptr);
#endif
diff --git a/src/registry.c b/src/registry.c
index b32625756c..84dc47aded 100644
--- a/src/registry.c
+++ b/src/registry.c
@@ -1,1016 +1,27 @@
#include "common.h"
-// ----------------------------------------------------------------------------
-// TODO
-//
-// 1. the default tracking cookie expires in 1 year, but the persons are not
-// removed from the db - this means the database only grows - ideally the
-// database should be cleaned in registry_save() for both on-disk and
-// on-memory entries.
-//
-// Cleanup:
-// i. Find all the PERSONs that have expired cookie
-// ii. For each of their PERSON_URLs:
-// - decrement the linked MACHINE links
-// - if the linked MACHINE has no other links, remove the linked MACHINE too
-// - remove the PERSON_URL
-//
-// 2. add protection to prevent abusing the registry by flooding it with
-// requests to fill the memory and crash it.
-//
-// Possible protections:
-// - limit the number of URLs per person
-// - limit the number of URLs per machine
-// - limit the number of persons
-// - limit the number of machines
-// - [DONE] limit the size of URLs
-// - [DONE] limit the size of PERSON_URL names
-// - limit the number of requests that add data to the registry,
-// per client IP per hour
-//
-// 3. lower memory requirements
-//
-// - embed avl structures directly into registry objects, instead of DICTIONARY
-// - store GUIDs in memory as UUID instead of char *
-// - do not track persons using the demo machines only
-// (i.e. start tracking them only when they access a non-demo machine)
-// - [DONE] do not track custom dashboards by default
-
-#define REGISTRY_URL_FLAGS_DEFAULT 0x00
-#define REGISTRY_URL_FLAGS_EXPIRED 0x01
-
-#define DICTIONARY_FLAGS DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE | DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
-
-#define GUID_LEN 36
-
-// ----------------------------------------------------------------------------
-// COMMON structures
-
-struct registry {
- int enabled;
-
- char machine_guid[GUID_LEN + 1];
-
- // entries counters / statistics
- unsigned long long persons_count;
- unsigned long long machines_count;
- unsigned long long usages_count;
- unsigned long long urls_count;
- unsigned long long persons_urls_count;
- unsigned long long machines_urls_count;
- unsigned long long log_count;
-
- // memory counters / statistics
- unsigned long long persons_memory;
- unsigned long long machines_memory;
- unsigned long long urls_memory;
- unsigned long long persons_urls_memory;
- unsigned long long machines_urls_memory;
-
- // configuration
- unsigned long long save_registry_every_entries;
- char *registry_domain;
- char *hostname;
- char *registry_to_announce;
- time_t persons_expiration; // seconds to expire idle persons
- int verify_cookies_redirects;
-
- size_t max_url_length;
- size_t max_name_length;
-
- // file/path names
- char *pathname;
- char *db_filename;
- char *log_filename;
- char *machine_guid_filename;
-
- // open files
- FILE *log_fp;
-
- // the database
- DICTIONARY *persons; // dictionary of PERSON *, with key the PERSON.guid
- DICTIONARY *machines; // dictionary of MACHINE *, with key the MACHINE.guid
- DICTIONARY *urls; // dictionary of URL *, with key the URL.url
-
- // concurrency locking
- // we keep different locks for different things
- // so that many tasks can be completed in parallel
- pthread_mutex_t persons_lock;
- pthread_mutex_t machines_lock;
- pthread_mutex_t urls_lock;
- pthread_mutex_t person_urls_lock;
- pthread_mutex_t machine_urls_lock;
- pthread_mutex_t log_lock;
-} registry;
-
-
-// ----------------------------------------------------------------------------
-// URL structures
-// Save memory by de-duplicating URLs
-// so instead of storing URLs all over the place
-// we store them here and we keep pointers elsewhere
-
-struct registry_url {
- uint32_t links; // the number of links to this URL - when none is left, we free it
- uint16_t len; // the length of the URL in bytes
- char url[1]; // the URL - dynamically allocated to more size
-};
-typedef struct registry_url REGISTRY_URL;
-
-
-// ----------------------------------------------------------------------------
-// MACHINE structures
-
-// For each MACHINE-URL pair we keep this
-struct registry_machine_url {
- REGISTRY_URL *url; // de-duplicated URL
-
- uint8_t flags;
-
- 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
-};
-typedef struct registry_machine_url REGISTRY_MACHINE_URL;
-
-// A machine
-struct registry_machine {
- char guid[GUID_LEN + 1]; // the GUID
-
- uint32_t links; // the number of REGISTRY_PERSON_URL linked to this machine
-
- DICTIONARY *machine_urls; // MACHINE_URL *
-
- 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
-};
-typedef struct registry_machine REGISTRY_MACHINE;
-
-
-// ----------------------------------------------------------------------------
-// PERSON structures
-
-// for each PERSON-URL pair we keep this
-struct registry_person_url {
- REGISTRY_URL *url; // de-duplicated URL
- REGISTRY_MACHINE *machine; // link the MACHINE of this URL
-
- uint8_t flags;
-
- 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
-
- char machine_name[1]; // the name of the machine, as known by the user
- // dynamically allocated to fit properly
-};
-typedef struct registry_person_url REGISTRY_PERSON_URL;
-
-// A person
-struct registry_person {
- char guid[GUID_LEN + 1]; // the person GUID
-
- DICTIONARY *person_urls; // dictionary of PERSON_URL *
-
- 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
-};
-typedef struct registry_person REGISTRY_PERSON;
+#include "registry_internals.h"
+#define REGISTRY_STATUS_OK "ok"
+#define REGISTRY_STATUS_FAILED "failed"
+#define REGISTRY_STATUS_DISABLED "disabled"
// ----------------------------------------------------------------------------
// REGISTRY concurrency locking
-static inline void registry_persons_lock(void) {
- pthread_mutex_lock(&registry.persons_lock);
-}
-
-static inline void registry_persons_unlock(void) {
- pthread_mutex_unlock(&registry.persons_lock);
-}
-
-static inline void registry_machines_lock(void) {
- pthread_mutex_lock(&registry.machines_lock);
-}
-
-static inline void registry_machines_unlock(void) {
- pthread_mutex_unlock(&registry.machines_lock);
-}
-
-static inline void registry_urls_lock(void) {
- pthread_mutex_lock(&registry.urls_lock);
-}
-
-static inline void registry_urls_unlock(void) {
- pthread_mutex_unlock(&registry.urls_lock);
-}
-
-// ideally, we should not lock the whole registry for
-// updating a person's urls.
-// however, to save the memory required for keeping a
-// mutex (40 bytes) per person, we do...
-static inline void registry_person_urls_lock(REGISTRY_PERSON *p) {
- (void)p;
- pthread_mutex_lock(&registry.person_urls_lock);
-}
-
-static inline void registry_person_urls_unlock(REGISTRY_PERSON *p) {
- (void)p;
- pthread_mutex_unlock(&registry.person_urls_lock);
+static inline void registry_lock(void) {
+ pthread_mutex_lock(&registry.lock);
}
-// ideally, we should not lock the whole registry for
-// updating a machine's urls.
-// however, to save the memory required for keeping a
-// mutex (40 bytes) per machine, we do...
-static inline void registry_machine_urls_lock(REGISTRY_MACHINE *m) {
- (void)m;
- pthread_mutex_lock(&registry.machine_urls_lock);
-}
-
-static inline void registry_machine_urls_unlock(REGISTRY_MACHINE *m) {
- (void)m;
- pthread_mutex_unlock(&registry.machine_urls_lock);
-}
-
-static inline void registry_log_lock(void) {
- pthread_mutex_lock(&registry.log_lock);
-}
-
-static inline void registry_log_unlock(void) {
- pthread_mutex_unlock(&registry.log_lock);
+static inline void registry_unlock(void) {
+ pthread_mutex_unlock(&registry.lock);
}
// ----------------------------------------------------------------------------
-// common functions
-
-// parse a GUID and re-generated to be always lower case
-// this is used as a protection against the variations of GUIDs
-static inline int registry_regenerate_guid(const char *guid, char *result) {
- uuid_t uuid;
- if(unlikely(uuid_parse(guid, uuid) == -1)) {
- info("Registry: GUID '%s' is not a valid GUID.", guid);
- return -1;
- }
- else {
- uuid_unparse_lower(uuid, result);
-
-#ifdef NETDATA_INTERNAL_CHECKS
- if(strcmp(guid, result))
- info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
-#endif /* NETDATA_INTERNAL_CHECKS */
- }
-
- return 0;
-}
-
-// make sure the names of the machines / URLs do not contain any tabs
-// (which are used as our separator in the database files)
-// and are properly trimmed (before and after)
-static inline char *registry_fix_machine_name(char *name, size_t *len) {
- char *s = name?name:"";
-
- // skip leading spaces
- while(*s && isspace(*s)) s++;
-
- // make sure all spaces are a SPACE
- char *t = s;
- while(*t) {
- if(unlikely(isspace(*t)))
- *t = ' ';
-
- t++;
- }
-
- // remove trailing spaces
- while(--t >= s) {
- if(*t == ' ')
- *t = '\0';
- else
- break;
- }
- t++;
-
- if(likely(len))
- *len = (t - s);
-
- return s;
-}
-
-static inline char *registry_fix_url(char *url, size_t *len) {
- return registry_fix_machine_name(url, len);
-}
-
-
-// ----------------------------------------------------------------------------
-// forward definition of functions
-
-extern REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when);
-extern REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
-
-
-// ----------------------------------------------------------------------------
-// URL
-
-static inline REGISTRY_URL *registry_url_allocate_nolock(const char *url, size_t urllen) {
- // protection from too big URLs
- if(urllen > registry.max_url_length)
- urllen = registry.max_url_length;
-
- debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(REGISTRY_URL) + urllen);
- REGISTRY_URL *u = mallocz(sizeof(REGISTRY_URL) + urllen);
-
- // a simple strcpy() should do the job
- // but I prefer to be safe, since the caller specified urllen
- u->len = (uint16_t)urllen;
- strncpyz(u->url, url, u->len);
- u->links = 0;
-
- registry.urls_memory += sizeof(REGISTRY_URL) + urllen;
-
- debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): indexing it", url);
- dictionary_set(registry.urls, u->url, u, sizeof(REGISTRY_URL));
-
- return u;
-}
-
-static inline REGISTRY_URL *registry_url_get_nolock(const char *url, size_t urllen) {
- debug(D_REGISTRY, "Registry: registry_url_get_nolock('%s')", url);
-
- REGISTRY_URL *u = dictionary_get(registry.urls, url);
- if(!u) {
- u = registry_url_allocate_nolock(url, urllen);
- registry.urls_count++;
- }
-
- return u;
-}
-
-static inline REGISTRY_URL *registry_url_get(const char *url, size_t urllen) {
- debug(D_REGISTRY, "Registry: registry_url_get('%s')", url);
-
- registry_urls_lock();
-
- REGISTRY_URL *u = registry_url_get_nolock(url, urllen);
-
- registry_urls_unlock();
-
- return u;
-}
-
-static inline void registry_url_link_nolock(REGISTRY_URL *u) {
- u->links++;
- debug(D_REGISTRY, "Registry: registry_url_link_nolock('%s'): URL has now %u links", u->url, u->links);
-}
-
-static inline void registry_url_unlink_nolock(REGISTRY_URL *u) {
- u->links--;
- if(!u->links) {
- debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
- dictionary_del(registry.urls, u->url);
- freez(u);
- }
- else
- debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
-}
-
-
-// ----------------------------------------------------------------------------
-// MACHINE
-
-static inline REGISTRY_MACHINE *registry_machine_find(const char *machine_guid) {
- debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
- return dictionary_get(registry.machines, machine_guid);
-}
-
-static inline REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) {
- debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(REGISTRY_MACHINE_URL));
-
- REGISTRY_MACHINE_URL *mu = mallocz(sizeof(REGISTRY_MACHINE_URL));
-
- // mu->persons = dictionary_create(DICTIONARY_FLAGS);
- // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
-
- mu->first_t = mu->last_t = (uint32_t)when;
- mu->usages = 1;
- mu->url = u;
- mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
-
- registry.machines_urls_memory += sizeof(REGISTRY_MACHINE_URL);
-
- debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url);
- dictionary_set(m->machine_urls, u->url, mu, sizeof(REGISTRY_MACHINE_URL));
- registry_url_link_nolock(u);
-
- return mu;
-}
-
-static inline REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) {
- debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(REGISTRY_MACHINE));
-
- REGISTRY_MACHINE *m = mallocz(sizeof(REGISTRY_MACHINE));
-
- strncpyz(m->guid, machine_guid, GUID_LEN);
-
- debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
- m->machine_urls = dictionary_create(DICTIONARY_FLAGS);
-
- m->first_t = m->last_t = (uint32_t)when;
- m->usages = 0;
-
- registry.machines_memory += sizeof(REGISTRY_MACHINE);
-
- registry.machines_count++;
- dictionary_set(registry.machines, m->guid, m, sizeof(REGISTRY_MACHINE));
-
- return m;
-}
-
-// 1. validate machine GUID
-// 2. if it is valid, find it or create it and return it
-// 3. if it is not valid, return NULL
-static inline REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
- REGISTRY_MACHINE *m = NULL;
-
- registry_machines_lock();
-
- if(likely(machine_guid && *machine_guid)) {
- // validate it is a GUID
- char buf[GUID_LEN + 1];
- if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
- info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
- else {
- machine_guid = buf;
- m = registry_machine_find(machine_guid);
- if(!m) m = registry_machine_allocate(machine_guid, when);
- }
- }
-
- registry_machines_unlock();
-
- return m;
-}
-
-
-// ----------------------------------------------------------------------------
-// PERSON
-
-static inline 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);
-}
-
-static inline REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
- // 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
- // but I prefer to be safe, since the caller specified urllen
- strncpyz(pu->machine_name, name, namelen);
-
- pu->machine = m;
- pu->first_t = pu->last_t = when;
- pu->usages = 1;
- pu->url = u;
- pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
- m->links++;
-
- 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_url_link_nolock(u);
-
- return pu;
-}
-
-static inline 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);
-
- 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_nolock(u);
-
- freez(pu);
-
- return tpu;
-}
-
-static inline 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));
-
- p = mallocz(sizeof(REGISTRY_PERSON));
-
- if(!person_guid) {
- for (; ;) {
- uuid_t uuid;
- uuid_generate(uuid);
- uuid_unparse_lower(uuid, p->guid);
-
- debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
- if (!dictionary_get(registry.persons, p->guid)) {
- debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
- break;
- }
- else
- info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
- }
- }
- else
- 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);
-
- p->first_t = p->last_t = when;
- p->usages = 0;
-
- registry.persons_memory += sizeof(REGISTRY_PERSON);
-
- registry.persons_count++;
- dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON));
-
- return p;
-}
-
-
-// 1. validate person GUID
-// 2. if it is valid, find it
-// 3. if it is not valid, create a new one
-// 4. return it
-static inline REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
- REGISTRY_PERSON *p = NULL;
-
- registry_persons_lock();
-
- if(person_guid && *person_guid) {
- char buf[GUID_LEN + 1];
- // validate it is a GUID
- if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
- info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
- else {
- person_guid = buf;
- p = registry_person_find(person_guid);
- }
- }
-
- if(!p) p = registry_person_allocate(NULL, when);
-
- registry_persons_unlock();
-
- return p;
-}
-
-// ----------------------------------------------------------------------------
-// LINKING OF OBJECTS
-
-static inline 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_urls_lock(p);
-
- REGISTRY_PERSON_URL *pu = dictionary_get(p->person_urls, 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);
- registry.persons_urls_count++;
- }
- else {
- debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
- pu->usages++;
- if(likely(pu->last_t < (uint32_t)when)) pu->last_t = 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.",
- 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.",
- p->guid, m->guid, u->url, pu->machine->guid);
- }
-
- pu->machine->links--;
- pu->machine = m;
- }
-
- if(strcmp(pu->machine_name, name)) {
- // the name of the PERSON_URL has changed !
- pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
- }
- }
-
- p->usages++;
- if(likely(p->last_t < (uint32_t)when)) p->last_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);
- pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
- }
-
- registry_person_urls_unlock(p);
-
- return pu;
-}
-
-static inline REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) {
- debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): searching for URL in machine", p->guid, m->guid, u->url);
-
- registry_machine_urls_lock(m);
-
- REGISTRY_MACHINE_URL *mu = dictionary_get(m->machine_urls, u->url);
- if(!mu) {
- debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
- mu = registry_machine_url_allocate(m, u, when);
- registry.machines_urls_count++;
- }
- else {
- debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
- mu->usages++;
- if(likely(mu->last_t < (uint32_t)when)) mu->last_t = when;
- }
-
- //debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing person in machine", p->guid, m->guid, u->url);
- //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
-
- m->usages++;
- if(likely(m->last_t < (uint32_t)when)) m->last_t = when;
-
- if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
- info("registry_machine_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url);
- mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
- }
-
- registry_machine_urls_unlock(m);
-
- return mu;
-}
-
-// ----------------------------------------------------------------------------
-// REGISTRY LOG LOAD/SAVE
-
-static inline int registry_should_save_db(void) {
- debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries);
- return registry.log_count > registry.save_registry_every_entries;
-}
-
-static inline void registry_log(const char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name) {
- if(likely(registry.log_fp)) {
- // we lock only if the file is open
- // to allow replaying the log at registry_log_load()
- registry_log_lock();
-
- if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
- action,
- p->last_t,
- p->guid,
- m->guid,
- name,
- u->url) < 0))
- error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
-
- // we increase the counter even on failures
- // so that the registry will be saved periodically
- registry.log_count++;
-
- registry_log_unlock();
-
- // this must be outside the log_lock(), or a deadlock will happen.
- // registry_save() checks the same inside the log_lock, so only
- // one thread will save the db
- if(unlikely(registry_should_save_db()))
- registry_save();
- }
-}
-
-static inline int registry_log_open_nolock(void) {
- if(registry.log_fp)
- fclose(registry.log_fp);
-
- registry.log_fp = fopen(registry.log_filename, "a");
-
- if(registry.log_fp) {
- if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
- error("Cannot set line buffering on registry log file.");
- return 0;
- }
-
- error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
- return -1;
-}
-
-static inline void registry_log_close_nolock(void) {
- if(registry.log_fp) {
- fclose(registry.log_fp);
- registry.log_fp = NULL;
- }
-}
-
-static inline void registry_log_recreate_nolock(void) {
- if(registry.log_fp != NULL) {
- registry_log_close_nolock();
-
- // open it with truncate
- registry.log_fp = fopen(registry.log_filename, "w");
- if(registry.log_fp) fclose(registry.log_fp);
- else error("Cannot truncate registry log '%s'", registry.log_filename);
-
- registry.log_fp = NULL;
-
- registry_log_open_nolock();
- }
-}
-
-int registry_log_load(void) {
- ssize_t line = -1;
-
- // closing the log is required here
- // otherwise we will append to it the values we read
- registry_log_close_nolock();
-
- debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
- FILE *fp = fopen(registry.log_filename, "r");
- if(!fp)
- error("Registry: cannot open registry file: %s", registry.log_filename);
- else {
- char *s, buf[4096 + 1];
- line = 0;
- size_t len = 0;
-
- while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
- line++;
-
- switch (s[0]) {
- case 'A': // accesses
- case 'D': // deletes
-
- // verify it is valid
- if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
- error("Registry: log line %zd is wrong (len = %zu).", line, len);
- continue;
- }
- s[1] = s[10] = s[47] = s[84] = '\0';
-
- // get the variables
- time_t when = strtoul(&s[2], NULL, 16);