diff options
author | Costa Tsaousis <costa@tsaousis.gr> | 2016-05-08 22:43:44 +0300 |
---|---|---|
committer | Costa Tsaousis <costa@tsaousis.gr> | 2016-05-08 22:43:44 +0300 |
commit | a1abb2f3398730f13a0704133ee1e52b4b6561a9 (patch) | |
tree | fbaf6c21232aafc427a2f961e5fde00fbcdf8b46 /src/registry.c | |
parent | e15a5a565bf78ea13aa1c4fda19403bacdcdca36 (diff) |
registry: working prototype with load/save
Diffstat (limited to 'src/registry.c')
-rw-r--r-- | src/registry.c | 730 |
1 files changed, 520 insertions, 210 deletions
diff --git a/src/registry.c b/src/registry.c index 2c8a653e3c..0944585c62 100644 --- a/src/registry.c +++ b/src/registry.c @@ -2,22 +2,28 @@ #include <config.h> #endif -// gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o registry ../src/registry.c ../src/dictionary.o ../src/log.o ../src/avl.o ../src/common.o -pthread -luuid -DHAVE_CONFIG_H +// gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o registry ../src/registry.c ../src/dictionary.o ../src/log.o ../src/avl.o ../src/common.o ../src/appconfig.o ../src/web_buffer.o ../src/storage_number.o -pthread -luuid -lm -DHAVE_CONFIG_H -DVARLIB_DIR="\"/tmp\"" #include <uuid/uuid.h> #include <inttypes.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> #include "log.h" #include "common.h" #include "dictionary.h" - -#define REGISTRY_MEMORY_ATTRIBUTE aligned +#include "appconfig.h" #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 + // ---------------------------------------------------------------------------- // COMMON structures @@ -29,9 +35,15 @@ struct registry { unsigned long long persons_urls_count; unsigned long long machines_urls_count; + char *pathname; + char *db_filename; + char *log_filename; + FILE *registry_log_fp; + 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 + } registry; @@ -41,9 +53,9 @@ struct registry { struct url { uint32_t links; - uint16_t url_length; - char url[]; -} __attribute__ (( REGISTRY_MEMORY_ATTRIBUTE )); + uint16_t len; + char url[1]; +}; typedef struct url URL; @@ -59,7 +71,7 @@ struct 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 -} __attribute__ (( REGISTRY_MEMORY_ATTRIBUTE )); +}; typedef struct machine_url MACHINE_URL; // A machine @@ -71,7 +83,7 @@ struct machine { 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 -} __attribute__ (( REGISTRY_MEMORY_ATTRIBUTE )); +}; typedef struct machine MACHINE; @@ -87,7 +99,7 @@ struct 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 -} __attribute__ (( REGISTRY_MEMORY_ATTRIBUTE )); +}; typedef struct person_url PERSON_URL; // A person @@ -99,30 +111,37 @@ struct person { 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 -} __attribute__ (( REGISTRY_MEMORY_ATTRIBUTE )); +}; typedef struct person PERSON; +extern PERSON *registry_request(const char *person_guid, const char *machine_guid, const char *url, time_t when); // ---------------------------------------------------------------------------- // URL -static inline URL *registry_url_get(const char *url) { - debug(D_DICTIONARY, "Registry: registry_url_get('%s')", url); - URL *u = dictionary_get(registry.urls, url); - if(!u) { - size_t len = strlen(url); +static inline URL *registry_url_allocate(const char *url) { + size_t len = strlen(url); - debug(D_DICTIONARY, "Registry: registry_url_get('%s'): allocating %zu bytes", url, sizeof(URL) + len + 1); - u = malloc(sizeof(URL) + len + 1); - if(!u) fatal("Cannot allocate %zu bytes for URL '%s'", sizeof(URL) + len + 1, url); + debug(D_REGISTRY, "Registry: registry_url_allocate('%s'): allocating %zu bytes", url, sizeof(URL) + len); + URL *u = malloc(sizeof(URL) + len); + if(!u) fatal("Cannot allocate %zu bytes for URL '%s'", sizeof(URL) + len); - strcpy(u->url, url); - u->links = 0; - u->url_length = len; + strcpy(u->url, url); + u->len = len; + u->links = 0; - debug(D_DICTIONARY, "Registry: registry_url_get('%s'): indexing it", url); - dictionary_set(registry.urls, url, u, sizeof(URL) + len + 1); + debug(D_REGISTRY, "Registry: registry_url_allocate('%s'): indexing it", url); + dictionary_set(registry.urls, u->url, u, sizeof(URL)); + return u; +} + +static inline URL *registry_url_get(const char *url) { + debug(D_REGISTRY, "Registry: registry_url_get('%s')", url); + + URL *u = dictionary_get(registry.urls, url); + if(!u) { + u = registry_url_allocate(url); registry.urls_count++; } @@ -131,81 +150,51 @@ static inline URL *registry_url_get(const char *url) { static inline void registry_url_link(URL *u) { u->links++; + debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): This URL has now %u links", u->url, u->links); } static inline void registry_url_unlink(URL *u) { u->links--; if(!u->links) { + debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): No more links for this URL", u->url); dictionary_del(registry.urls, u->url); free(u); } + else + debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): This URL has %u links left", u->url, u->links); } // ---------------------------------------------------------------------------- // MACHINE -int dump_machine_url(void *entry, void *nothing) { - (void)nothing; - - MACHINE_URL *mu = entry; - - fprintf(stderr, "\n\tURL '%s'\n\t\tfirst seen %u, last seen %u, usages %u, flags 0x%02x\n", - mu->url->url, - mu->first_t, - mu->last_t, - mu->usages, - mu->flags - ); - - return 0; -} - -int dump_machine(void *entry, void *nothing) { - (void)nothing; - - MACHINE *m = entry; - - fprintf(stderr, "MACHINE '%s'\n\tfirst seen %u, last seen %u, usages %u\n", - m->guid, - (uint32_t)m->first_t, - (uint32_t)m->last_t, - m->usages - ); - - dictionary_get_all(m->urls, dump_machine_url, NULL); - return 0; +static inline 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); } -MACHINE *registry_machine_load(const char *machine_guid) { - debug(D_REGISTRY, "Registry: registry_machine_load('%s')", machine_guid); - (void)machine_guid; +static inline MACHINE_URL *registry_machine_url_allocate(MACHINE *m, URL *u, time_t when) { + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL)); - debug(D_REGISTRY, "Registry: registry_machine_load('%s'): not found", machine_guid); - return NULL; -} + MACHINE_URL *mu = malloc(sizeof(MACHINE_URL)); + if(!mu) fatal("registry_machine_link_to_url('%s', '%s'): cannot allocate %zu bytes.", m->guid, u->url, sizeof(MACHINE_URL)); -int registry_machine_save(MACHINE *m) { - debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid); + // mu->persons = dictionary_create(DICTIONARY_FLAGS); + // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON)); -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\nSAVING "); - dump_machine(m, NULL); -#endif /* REGISTRY_STDOUT_DUMP */ + mu->first_t = mu->last_t = when; + mu->usages = 1; + mu->url = u; + mu->flags = REGISTRY_URL_FLAGS_DEFAULT; - return -1; -} - -MACHINE *registry_machine_find(const char *machine_guid) { - debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid); + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url); + dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL)); + registry_url_link(u); - MACHINE *m = dictionary_get(registry.machines, machine_guid); - if(!m) m = registry_machine_load(machine_guid); - return m; + return mu; } - -MACHINE *registry_machine_allocate(const char *machine_guid) { +static inline 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(MACHINE)); MACHINE *m = calloc(1, sizeof(MACHINE)); @@ -214,9 +203,9 @@ MACHINE *registry_machine_allocate(const char *machine_guid) { strncpy(m->guid, machine_guid, 36); debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid); - m->urls = dictionary_create(DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); + m->urls = dictionary_create(DICTIONARY_FLAGS); - m->first_t = m->last_t = time(NULL); + m->first_t = m->last_t = when; m->usages = 0; dictionary_set(registry.machines, m->guid, m, sizeof(MACHINE)); @@ -224,7 +213,10 @@ MACHINE *registry_machine_allocate(const char *machine_guid) { return m; } -MACHINE *registry_machine_get(const char *machine_guid) { +// 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 MACHINE *registry_machine_get(const char *machine_guid, time_t when) { MACHINE *m = NULL; if(likely(machine_guid && *machine_guid)) { @@ -242,7 +234,7 @@ MACHINE *registry_machine_get(const char *machine_guid) { machine_guid = buf; m = registry_machine_find(machine_guid); if(!m) { - m = registry_machine_allocate(machine_guid); + m = registry_machine_allocate(machine_guid, when); registry.machines_count++; } } @@ -255,65 +247,30 @@ MACHINE *registry_machine_get(const char *machine_guid) { // ---------------------------------------------------------------------------- // PERSON -int dump_person_url(void *entry, void *nothing) { - (void)nothing; - - PERSON_URL *pu = entry; - - fprintf(stderr, "\n\tURL '%s'\n\t\tfirst seen %u, last seen %u, usages %u, flags 0x%02x\n", - pu->url->url, - pu->first_t, - pu->last_t, - pu->usages, - pu->flags - ); - - return 0; -} - -int dump_person(void *entry, void *nothing) { - (void)nothing; - - PERSON *p = entry; - - fprintf(stderr, "PERSON '%s'\n\tfirst seen %u, last seen %u, usages %u\n", - p->guid, - p->first_t, - p->last_t, - p->usages - ); - - dictionary_get_all(p->urls, dump_person_url, NULL); - return 0; +static inline 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 registry_person_save(PERSON *p) { - debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid); +static inline PERSON_URL *registry_person_url_allocate(PERSON *p, MACHINE *m, URL *u, time_t when) { + debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(PERSON_URL)); + PERSON_URL *pu = malloc(sizeof(PERSON_URL)); + if(!pu) fatal("registry_person_link_to_url('%s', '%s', '%s'): cannot allocate %zu bytes.", p->guid, m->guid, u->url, sizeof(PERSON_URL)); -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\nSAVING "); - dump_person(p, NULL); -#endif /* REGISTRY_STDOUT_DUMP */ + pu->machine = m; + pu->first_t = pu->last_t = when; + pu->usages = 1; + pu->url = u; + pu->flags = REGISTRY_URL_FLAGS_DEFAULT; - return -1; -} + debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url); + dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL)); + registry_url_link(u); -PERSON *registry_person_load(const char *person_guid) { - debug(D_REGISTRY, "Registry: registry_person_load('%s')", person_guid); - (void)person_guid; - - debug(D_REGISTRY, "Registry: registry_person_load('%s'): not found", person_guid); - return NULL; -} - -PERSON *registry_person_find(const char *person_guid) { - debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid); - PERSON *p = dictionary_get(registry.persons, person_guid); - if(!p) p = registry_person_load(person_guid); - return p; + return pu; } -PERSON *registry_person_allocate(const char *person_guid) { +static inline PERSON *registry_person_allocate(const char *person_guid, time_t when) { PERSON *p = NULL; debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON)); @@ -344,16 +301,21 @@ PERSON *registry_person_allocate(const char *person_guid) { } debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid); - p->urls = dictionary_create(DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); + p->urls = dictionary_create(DICTIONARY_FLAGS); - p->first_t = p->last_t = time(NULL); + p->first_t = p->last_t = when; p->usages = 0; dictionary_set(registry.persons, p->guid, p, sizeof(PERSON)); return p; } -PERSON *registry_person_get(const char *person_guid) { + +// 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 PERSON *registry_person_get(const char *person_guid, time_t when) { PERSON *p = NULL; if(person_guid && *person_guid) { @@ -375,33 +337,23 @@ PERSON *registry_person_get(const char *person_guid) { } if(!p) { - p = registry_person_allocate(NULL); + p = registry_person_allocate(NULL, when); registry.persons_count++; } return p; } - // ---------------------------------------------------------------------------- // LINKING OF OBJECTS -PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u) { +static inline PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u, 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); PERSON_URL *pu = dictionary_get(p->urls, u->url); if(!pu) { - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found, allocating %zu bytes", p->guid, m->guid, u->url, sizeof(PERSON_URL)); - pu = malloc(sizeof(PERSON_URL)); - pu->machine = m; - pu->first_t = pu->last_t = time(NULL); - pu->usages = 1; - pu->url = u; - pu->flags = REGISTRY_URL_FLAGS_DEFAULT; - - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url); - dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL)); - registry_url_link(u); + 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, when); registry.persons_urls_count++; } else { @@ -421,6 +373,7 @@ PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u) { } p->usages++; + p->last_t = when; if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url); @@ -428,22 +381,13 @@ PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u) { return pu; } -MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, URL *u) { +static inline MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, 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); MACHINE_URL *mu = dictionary_get(m->urls, u->url); if(!mu) { - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found, allocating %zu bytes", p->guid, m->guid, u->url, sizeof(MACHINE_URL)); - mu = malloc(sizeof(MACHINE_URL)); - //mu->persons = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); - mu->first_t = mu->last_t = time(NULL); - mu->usages = 1; - mu->url = u; - mu->flags = REGISTRY_URL_FLAGS_DEFAULT; - - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing URL in machine", p->guid, m->guid, u->url); - dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL)); - registry_url_link(u); + 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 { @@ -455,6 +399,7 @@ MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, URL *u) { //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON)); m->usages++; + m->last_t = when; if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url); @@ -462,40 +407,388 @@ MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, URL *u) { return mu; } - // ---------------------------------------------------------------------------- -// REGISTRY REQUESTS +// REGISTRY LOG LOAD/SAVE + +static inline void registry_log(const char action, PERSON *p, MACHINE *m, URL *u) { + if(likely(registry.registry_log_fp)) + fprintf(registry.registry_log_fp, "%c\t%08x\t%s\t%s\t%s\n", + action, + p->last_t, + p->guid, + m->guid, + u->url + ); +} -int registry_save(void) { - return -1; +void registry_log_open(void) { + registry.registry_log_fp = fopen(registry.log_filename, "a"); + + if(registry.registry_log_fp) { + if (setvbuf(registry.registry_log_fp, NULL, _IOLBF, 0) != 0) + error("Cannot set line buffering on registry log file."); + } +} + +void registry_log_close(void) { + if(registry.registry_log_fp) + fclose(registry.registry_log_fp); + + registry.registry_log_fp = NULL; +} + +void registry_log_recreate(void) { + if(registry.registry_log_fp != NULL) { + fclose(registry.registry_log_fp); + + registry.registry_log_fp = fopen(registry.log_filename, "w"); + if(registry.registry_log_fp) fclose(registry.registry_log_fp); + registry.registry_log_fp = NULL; + + registry_log_open(); + } } -PERSON *registry_request(const char *person_guid, const char *machine_guid, const char *url) { +int registry_log_load(void) { + char *s, buf[4096 + 1]; + size_t line = 0; + + registry_log_close(); + + 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); + return 0; + } + + size_t len = 0; + while((s = fgets_trim_len(buf, 4096, fp, &len))) { + line++; + + switch(s[0]) { + case 'A': + // verify it is valid + if(unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) + error("Registry log line %u is wrong (len = %zu).", line, len); + + s[1] = s[10] = s[47] = s[84] = '\0'; + registry_request(&s[11], &s[48], &s[85], strtoul(&s[2], NULL, 16)); + break; + + default: + error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.log_filename, s); + break; + } + } + + registry_log_open(); + + return 0; +} + + +// ---------------------------------------------------------------------------- +// REGISTRY REQUESTS + +PERSON *registry_request(const char *person_guid, const char *machine_guid, const char *url, time_t when) { debug(D_REGISTRY, "registry_request('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url); - MACHINE *m = registry_machine_get(machine_guid); + MACHINE *m = registry_machine_get(machine_guid, when); if(!m) return NULL; URL *u = registry_url_get(url); + PERSON *p = registry_person_get(person_guid, when); - PERSON *p = registry_person_get(person_guid); - registry_person_link_to_url(p, m, u); - registry_machine_link_to_url(p, m, u); + registry_person_link_to_url(p, m, u, when); + registry_machine_link_to_url(p, m, u, when); - debug(D_REGISTRY, "Registry: registry_request('%s', '%s', '%s'): saving", person_guid, machine_guid, url); - registry_person_save(p); - registry_machine_save(m); + registry_log('A', p, m, u); registry.usages_count++; - registry_save(); - return p; } + +// ---------------------------------------------------------------------------- +// REGISTRY LOAD/SAVE + +int registry_machine_save_url(void *entry, void *file) { + MACHINE_URL *mu = entry; + FILE *fp = file; + + debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url); + + int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n", + mu->first_t, + mu->last_t, + mu->usages, + mu->flags, + mu->url->url + ); + + return ret; +} + +int registry_machine_save(void *entry, void *file) { + MACHINE *m = entry; + FILE *fp = file; + + debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid); + + int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n", + m->first_t, + m->last_t, + m->usages, + m->guid + ); + + if(ret >= 0) { + int ret2 = dictionary_get_all(m->urls, registry_machine_save_url, fp); + if(ret2 < 0) return ret2; + ret += ret2; + } + + return ret; +} + +static inline int registry_person_save_url(void *entry, void *file) { + PERSON_URL *pu = entry; + FILE *fp = file; + + debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url); + + int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\n", + pu->first_t, + pu->last_t, + pu->usages, + pu->flags, + pu->machine->guid, + pu->url->url + ); + + return ret; +} + +static inline int registry_person_save(void *entry, void *file) { + PERSON *p = entry; + FILE *fp = file; + + debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid); + + int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n", + p->first_t, + p->last_t, + p->usages, + p->guid + ); + + if(ret >= 0) { + int ret2 = dictionary_get_all(p->urls, registry_person_save_url, fp); + if (ret2 < 0) return ret2; + ret += ret2; + } + + return ret; +} + +static int registry_save(void) { + char tmp_filename[FILENAME_MAX + 1]; + char old_filename[FILENAME_MAX + 1]; + + snprintf(old_filename, FILENAME_MAX, "%s.old", registry.db_filename); + snprintf(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename); + + debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename); + FILE *fp = fopen(tmp_filename, "w"); + if(!fp) { + error("Registry: Cannot create file: %s", tmp_filename); + return -1; + } + + debug(D_REGISTRY, "Saving all machines"); + int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp); + if(bytes1 < 0) { + error("Registry: Cannot save registry machines - return value %d", bytes1); + fclose(fp); + return bytes1; + } + debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1); + + debug(D_REGISTRY, "Saving all persons"); + int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp); + if(bytes2 < 0) { + error("Registry: Cannot save registry persons - return value %d", bytes2); + fclose(fp); + return bytes2; + } + debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2); + + fclose(fp); + + errno = 0; + + // remove the .old db + debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename); + if(unlink(old_filename) == -1 && errno != ENOENT) + error("Registry: cannot remove old registry file '%s'", old_filename); + + // rename the db to .old + debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename); + if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT) + error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, registry.db_filename); + + else { + // remove the database (it is saved in .old) + debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename); + if (unlink(registry.db_filename) == -1 && errno != ENOENT) + error("Registry: cannot remove old registry file '%s'", registry.db_filename); + + // move the .tmp to make it active + debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename); + if (link(tmp_filename, registry.db_filename) == -1) { + error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, + registry.db_filename); + + // move the .old back + debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename); + if(link(old_filename, registry.db_filename) == -1) + error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename); + } + else { + debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename); + if(unlink(tmp_filename) == -1) + error("Registry: cannot remove tmp registry file '%s'", tmp_filename); + + // it has been moved successfully + // discard the current registry log + registry_log_recreate(); + } + } + + return -1; +} + +static inline size_t registry_load(void) { + char *s, buf[4096 + 1]; + PERSON *p = NULL; + MACHINE *m = NULL; + URL *u = NULL; + size_t line = 0; + + debug(D_REGISTRY, "Registry: loading active db from: %s", registry.db_filename); + FILE *fp = fopen(registry.db_filename, "r"); + if(!fp) { + error("Registry: cannot open registry file: %s", registry.db_filename); + return 0; + } + + size_t len = 0; + while((s = fgets_trim_len(buf, 4096, fp, &len))) { + line++; + + debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s); + + switch(*s) { + case 'P': // person + m = NULL; + // verify it is valid + if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) + error("Registry person line %u is wrong (len = %zu).", line, len); + + s[1] = s[10] = s[19] = s[28] = '\0'; + p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16)); + p->last_t = strtoul(&s[11], NULL, 16); + p->usages = strtoul(&s[20], NULL, 16); + debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages); + break; + + case 'M': // machine + p = NULL; + // verify it is valid + if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) + error("Registry person line %u is wrong (len = %zu).", line, len); + + s[1] = s[10] = s[19] = s[28] = '\0'; + m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16)); + m->last_t = strtoul(&s[11], NULL, 16); + m->usages = strtoul(&s[20], NULL, 16); + debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages); + break; + + case 'U': // person URL + if(unlikely(!p)) { + error("Registry: ignoring line %zu, no person loaded: %s", line, s); + break; + } + + // verify it is valid + if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') + error("Registry person URL line %u is wrong (len = %zu).", line, len); + + s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0'; + u = registry_url_allocate(&s[69]); + + time_t first_t = strtoul(&s[2], NULL, 16); + + m = registry_machine_find(&s[32]); + if(!m) m = registry_machine_allocate(&s[32], first_t); + + PERSON_URL *pu = registry_person_url_allocate(p, m, u, first_t); + pu->last_t = strtoul(&s[11], NULL, 16); + pu->usages = strtoul(&s[20], NULL, 16); + pu->flags = strtoul(&s[29], NULL, 16); + debug(D_REGISTRY, "Registry loaded person URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags); + break; + + case 'V': // machine URL + if(unlikely(!m)) { + error("Registry: ignoring line %zu, no machine loaded: %s", line, s); + break; + } + + // verify it is valid + if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') + error("Registry person URL line %u is wrong (len = %zu).", line, len); + + s[1] = s[10] = s[19] = s[28] = s[31] = '\0'; + u = registry_url_allocate(&s[32]); + + MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16)); + mu->last_t = strtoul(&s[11], NULL, 16); + mu->usages = strtoul(&s[20], NULL, 16); + mu->flags = strtoul(&s[29], NULL, 16); + debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags); + break; + + default: + error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s); + break; + } + } + fclose(fp); + + registry_log_load(); + + return line; +} + // ---------------------------------------------------------------------------- // REGISTRY void registry_init(void) { + char filename[FILENAME_MAX + 1]; + + registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR); + if(mkdir(registry.pathname, 0644) == -1 && errno != EEXIST) + error("Cannot create directory '%s'", registry.pathname); + + snprintf(filename, FILENAME_MAX, "%s/%s", registry.pathname, "registry.db"); + registry.db_filename = config_get("registry", "registry db file", filename); + + snprintf(filename, FILENAME_MAX, "%s/%s", registry.pathname, "registry-log.db"); + registry.log_filename = config_get("registry", "registry log file", filename); + registry.persons_count = 0; registry.machines_count = 0; registry.usages_count = 0; @@ -504,34 +797,33 @@ void registry_init(void) { registry.machines_urls_count = 0; debug(D_REGISTRY, "Registry: creating global registry dictionary for persons."); - registry.persons = dictionary_create(DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); + registry.persons = dictionary_create(DICTIONARY_FLAGS); debug(D_REGISTRY, "Registry: creating global registry dictionary for machines."); - registry.machines = dictionary_create(DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); + registry.machines = dictionary_create(DICTIONARY_FLAGS); debug(D_REGISTRY, "Registry: creating global registry dictionary for urls."); - registry.urls = dictionary_create(DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_SINGLE_THREADED); + registry.urls = dictionary_create(DICTIONARY_FLAGS); + + registry_log_open(); + registry_load(); } void registry_free(void) { while(registry.persons->values_index.root) { PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value; -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages); -#endif /* REGISTRY_STDOUT_DUMP */ + // fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages); while(p->urls->values_index.root) { PERSON_URL *pu = ((NAME_VALUE *)p->urls->values_index.root)->value; -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags); -#endif /* REGISTRY_STDOUT_DUMP */ + // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags); debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", pu->url->url, p->guid); dictionary_del(p->urls, pu->url->url); - debug(D_REGISTRY, "Registry: unlinking url '%s'", pu->url->url); + debug(D_REGISTRY, "Registry: unlinking url '%s' from person", pu->url->url); registry_url_unlink(pu->url); debug(D_REGISTRY, "Registry: freeing person url"); @@ -551,16 +843,12 @@ void registry_free(void) { while(registry.machines->values_index.root) { MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value; -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages); -#endif /* REGISTRY_STDOUT_DUMP */ + // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages); while(m->urls->values_index.root) { MACHINE_URL *mu = ((NAME_VALUE *)m->urls->values_index.root)->value; -#ifdef REGISTRY_STDOUT_DUMP - fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags); -#endif /* REGISTRY_STDOUT_DUMP */ + // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags); //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url); //dictionary_destroy(mu->persons); @@ -568,7 +856,7 @@ void registry_free(void) { debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid); dictionary_del(m->urls, mu->url->url); - debug(D_REGISTRY, "Registry: unlinking url '%s'", mu->url); + debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url); registry_url_unlink(mu->url); debug(D_REGISTRY, "Registry: freeing machine url"); @@ -595,6 +883,10 @@ void registry_free(void) { dictionary_destroy(registry.urls); } + +// ---------------------------------------------------------------------------- +// TESTS + int test1(int argc, char **argv) { void print_stats(uint32_t requests, unsigned long long start, unsigned long long end) { @@ -609,8 +901,8 @@ int test1(int argc, char **argv) { (void) argc; (void) argv; - uint32_t u, users = 500000; - |