-static inline void registry_persons_lock(void) {
- pthread_mutex_lock(®istry.persons_lock);
-}
-
-static inline void registry_persons_unlock(void) {
- pthread_mutex_unlock(®istry.persons_lock);
-}
-
-static inline void registry_machines_lock(void) {
- pthread_mutex_lock(®istry.machines_lock);
-}
-
-static inline void registry_machines_unlock(void) {
- pthread_mutex_unlock(®istry.machines_lock);
-}
-
-static inline void registry_urls_lock(void) {
- pthread_mutex_lock(®istry.urls_lock);
-}
-
-static inline void registry_urls_unlock(void) {
- pthread_mutex_unlock(®istry.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(®istry.person_urls_lock);
-}
-
-static inline void registry_person_urls_unlock(REGISTRY_PERSON *p) {
- (void)p;
- pthread_mutex_unlock(®istry.person_urls_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(®istry.machine_urls_lock);
-}
-
-static inline void registry_machine_urls_unlock(REGISTRY_MACHINE *m) {
- (void)m;
- pthread_mutex_unlock(®istry.machine_urls_lock);
-}
-
-static inline void registry_log_lock(void) {
- pthread_mutex_lock(®istry.log_lock);
-}
-
-static inline void registry_log_unlock(void) {
- pthread_mutex_unlock(®istry.log_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();
- }