summaryrefslogtreecommitdiffstats
path: root/src/registry.c
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@tsaousis.gr>2016-05-08 22:43:44 +0300
committerCosta Tsaousis <costa@tsaousis.gr>2016-05-08 22:43:44 +0300
commita1abb2f3398730f13a0704133ee1e52b4b6561a9 (patch)
treefbaf6c21232aafc427a2f961e5fde00fbcdf8b46 /src/registry.c
parente15a5a565bf78ea13aa1c4fda19403bacdcdca36 (diff)
registry: working prototype with load/save
Diffstat (limited to 'src/registry.c')
-rw-r--r--src/registry.c730
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;
-