]> arthur.barton.de Git - netdata.git/blobdiff - src/registry_log.c
removed over-optimization at the registry to simplify its logic and remove race condi...
[netdata.git] / src / registry_log.c
diff --git a/src/registry_log.c b/src/registry_log.c
new file mode 100644 (file)
index 0000000..3229a34
--- /dev/null
@@ -0,0 +1,133 @@
+#include "registry_internals.h"
+
+void registry_log(const char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name) {
+    if(likely(registry.log_fp)) {
+        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++;
+
+        // this must be outside the log_lock(), or a deadlock will happen.
+        // registry_db_save() checks the same inside the log_lock, so only
+        // one thread will save the db
+        if(unlikely(registry_db_should_be_saved()))
+            registry_db_save();
+    }
+}
+
+int registry_log_open(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;
+}
+
+void registry_log_close(void) {
+    if(registry.log_fp) {
+        fclose(registry.log_fp);
+        registry.log_fp = NULL;
+    }
+}
+
+void registry_log_recreate(void) {
+    if(registry.log_fp != NULL) {
+        registry_log_close();
+
+        // 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();
+    }
+}
+
+ssize_t 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();
+
+    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);
+                    char *person_guid = &s[11];
+                    char *machine_guid = &s[48];
+                    char *name = &s[85];
+
+                    // skip the name to find the url
+                    char *url = name;
+                    while(*url && *url != '\t') url++;
+                    if(!*url) {
+                        error("Registry: log line %zd does not have a url.", line);
+                        continue;
+                    }
+                    *url++ = '\0';
+
+                    // make sure the person exists
+                    // without this, a new person guid will be created
+                    REGISTRY_PERSON *p = registry_person_find(person_guid);
+                    if(!p) p = registry_person_allocate(person_guid, when);
+
+                    if(s[0] == 'A')
+                        registry_request_access(p->guid, machine_guid, url, name, when);
+                    else
+                        registry_request_delete(p->guid, machine_guid, url, name, when);
+
+                    registry.log_count++;
+                    break;
+
+                default:
+                    error("Registry: ignoring line %zd of filename '%s': %s.", line, registry.log_filename, s);
+                    break;
+            }
+        }
+
+        fclose(fp);
+    }
+
+    // open the log again
+    registry_log_open();
+
+    return line;
+}