]> arthur.barton.de Git - netdata.git/commitdiff
diskspace statistics are now a separate thread, to isolate the delays introduced...
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sat, 14 Jan 2017 13:47:02 +0000 (15:47 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sat, 14 Jan 2017 13:47:02 +0000 (15:47 +0200)
CMakeLists.txt
src/Makefile.am
src/common.h
src/main.c
src/plugin_proc_diskspace.c [new file with mode: 0644]
src/plugin_proc_diskspace.h [new file with mode: 0644]
src/proc_diskstats.c

index 49ae6b0c88d6711250c27b134a32871ad3a7645a..e49fd7963246c765f7ff7f4f50a0b26df48d63b4 100755 (executable)
@@ -101,7 +101,7 @@ set(NETDATA_SOURCE_FILES
         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 src/proc_uptime.c src/sys_devices_system_edac_mc.c)
+        src/registry_machine.h src/registry_internals.c src/registry_init.c src/registry_db.c src/registry_log.c src/proc_uptime.c src/sys_devices_system_edac_mc.c src/plugin_proc_diskspace.c src/plugin_proc_diskspace.h)
 
 set(APPS_PLUGIN_SOURCE_FILES
         src/appconfig.c
index 5533c95167cfb72f5947c90785f54a7630a621c1..616a2786e568739c7424c3045b638e7f5b490a33 100644 (file)
@@ -86,6 +86,7 @@ else
 netdata_SOURCES += \
        ipc.c ipc.h \
        plugin_proc.c plugin_proc.h \
+       plugin_proc_diskspace.c plugin_proc_diskspace.h \
        proc_diskstats.c \
        proc_interrupts.c \
        proc_softirqs.c \
index de4ff7a5d89190d06b3cccc950f50ee71e906760..04521023cbff3f9e5dcf7dbf2536082de9ade417 100644 (file)
 #include "plugin_macos.h"
 #else
 #include "plugin_proc.h"
+#include "plugin_proc_diskspace.h"
 #endif /* __FreeBSD__, __APPLE__*/
 
 #include "plugin_tc.h"
index c4869218f76fec08685058321d23f61f8c633d73..36b596c5a067d1a9206795c46793066b65039fbb 100644 (file)
@@ -45,6 +45,7 @@ struct netdata_static_thread static_threads[] = {
     {"macos",              "plugins",   "macos",      1, NULL, NULL, macos_main},
 #else
     {"proc",               "plugins",   "proc",       1, NULL, NULL, proc_main},
+    {"diskspace",          "plugins",   "diskspace",  1, NULL, NULL, proc_diskspace_main},
 #endif /* __FreeBSD__, __APPLE__*/
     {"cgroups",            "plugins",   "cgroups",    1, NULL, NULL, cgroups_main},
     {"check",              "plugins",   "checks",     0, NULL, NULL, checks_main},
diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c
new file mode 100644 (file)
index 0000000..7e606db
--- /dev/null
@@ -0,0 +1,227 @@
+#include "common.h"
+
+#ifndef NETDATA_RELOAD_MOUNTINFO_EVERY
+#define NETDATA_RELOAD_MOUNTINFO_EVERY 60
+#endif
+
+#define DELAULT_EXLUDED_PATHS "/proc/ /sys/ /var/run/user/ /run/user/"
+
+static struct mountinfo *disk_mountinfo_root = NULL;
+
+static inline void mountinfo_reload(int force) {
+    static time_t last_loaded = 0;
+    time_t now = now_realtime_sec();
+
+    if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
+        // mountinfo_free() can be called with NULL disk_mountinfo_root
+        mountinfo_free(disk_mountinfo_root);
+
+        // re-read mountinfo in case something changed
+        disk_mountinfo_root = mountinfo_read();
+
+        last_loaded = now;
+    }
+}
+
+// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
+// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
+struct mount_point_metadata {
+    int do_space;
+    int do_inodes;
+    int update_every;
+};
+
+static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
+    const char *family = mi->mount_point;
+    const char *disk = mi->persistent_id;
+
+    static DICTIONARY *mount_points = NULL;
+    static NETDATA_SIMPLE_PATTERN *excluded_mountpoints = NULL;
+    int do_space, do_inodes;
+
+    if(unlikely(!mount_points)) {
+        const char *s;
+
+        if(config_exists("plugin:proc:/proc/diskstats", "exclude space metrics on paths") && !config_exists("plugin:proc:diskspace", "exclude space metrics on paths")) {
+            // the config exists in the old section
+            s = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
+
+            // set it to the new section
+            config_set("plugin:proc:diskspace", "exclude space metrics on paths", s);
+        }
+        else
+            s = config_get("plugin:proc:diskspace", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
+
+        mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+        excluded_mountpoints = netdata_simple_pattern_list_create(s, NETDATA_SIMPLE_PATTERN_MODE_PREFIX);
+    }
+
+    struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
+    if(unlikely(!m)) {
+        char var_name[4096 + 1];
+        snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
+
+        int def_space = config_get_boolean_ondemand("plugin:proc:diskspace", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
+        int def_inodes = config_get_boolean_ondemand("plugin:proc:diskspace", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
+
+        if(unlikely(netdata_simple_pattern_list_matches(excluded_mountpoints, mi->mount_point))) {
+            def_space = CONFIG_ONDEMAND_NO;
+            def_inodes = CONFIG_ONDEMAND_NO;
+        }
+
+        do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
+        do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
+
+        struct mount_point_metadata mp = {
+                .do_space = do_space,
+                .do_inodes = do_inodes,
+                .update_every = rrd_update_every
+        };
+
+        dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
+    }
+    else {
+        do_space = m->do_space;
+        do_inodes = m->do_inodes;
+        update_every = m->update_every;
+    }
+
+    if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
+        return;
+
+    struct statvfs buff_statvfs;
+    if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
+        error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
+        return;
+    }
+
+    // taken from get_fs_usage() found in coreutils
+    unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
+
+    fsblkcnt_t bavail         = buff_statvfs.f_bavail;
+    fsblkcnt_t btotal         = buff_statvfs.f_blocks;
+    fsblkcnt_t bavail_root    = buff_statvfs.f_bfree;
+    fsblkcnt_t breserved_root = bavail_root - bavail;
+    fsblkcnt_t bused;
+    if(likely(btotal >= bavail_root))
+        bused = btotal - bavail_root;
+    else
+        bused = bavail_root - btotal;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+    if(unlikely(btotal != bavail + breserved_root + bused))
+        error("Disk block statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)btotal, (unsigned long long)bavail, (unsigned long long)breserved_root, (unsigned long long)bused);
+#endif
+
+    // --------------------------------------------------------------------------
+
+    fsfilcnt_t favail         = buff_statvfs.f_favail;
+    fsfilcnt_t ftotal         = buff_statvfs.f_files;
+    fsfilcnt_t favail_root    = buff_statvfs.f_ffree;
+    fsfilcnt_t freserved_root = favail_root - favail;
+    fsfilcnt_t fused          = ftotal - favail_root;
+
+#ifdef NETDATA_INTERNAL_CHECKS
+    if(unlikely(btotal != bavail + breserved_root + bused))
+        error("Disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused);
+#endif
+
+    // --------------------------------------------------------------------------
+
+    RRDSET *st;
+
+    if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
+        st = rrdset_find_bytype("disk_space", disk);
+        if(unlikely(!st)) {
+            char title[4096 + 1];
+            snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
+            st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "avail", (collected_number)bavail);
+        rrddim_set(st, "used", (collected_number)bused);
+        rrddim_set(st, "reserved_for_root", (collected_number)breserved_root);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------------
+
+    if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
+        st = rrdset_find_bytype("disk_inodes", disk);
+        if(unlikely(!st)) {
+            char title[4096 + 1];
+            snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
+            st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "avail", (collected_number)favail);
+        rrddim_set(st, "used", (collected_number)fused);
+        rrddim_set(st, "reserved_for_root", (collected_number)freserved_root);
+        rrdset_done(st);
+    }
+}
+
+void *proc_diskspace_main(void *ptr) {
+    struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+
+    info("DISKSPACE thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
+
+    int update_every = (int)config_get_number("plugin:proc:diskspace", "update every", rrd_update_every);
+    if(update_every < rrd_update_every)
+        update_every = rrd_update_every;
+
+    usec_t step = update_every * USEC_PER_SEC;
+    for(;;) {
+        usec_t now = now_monotonic_usec();
+        usec_t next = now - (now % step) + step;
+
+        while(now < next) {
+            sleep_usec(next - now);
+            now = now_monotonic_usec();
+        }
+
+        if(unlikely(netdata_exit)) break;
+
+        // --------------------------------------------------------------------------
+        // this is smart enough not to reload it every time
+
+        mountinfo_reload(0);
+
+        // --------------------------------------------------------------------------
+        // disk space metrics
+
+        struct mountinfo *mi;
+        for(mi = disk_mountinfo_root; mi; mi = mi->next) {
+
+            if(unlikely(mi->flags &
+                        (MOUNTINFO_IS_DUMMY | MOUNTINFO_IS_BIND | MOUNTINFO_IS_SAME_DEV | MOUNTINFO_NO_STAT |
+                         MOUNTINFO_NO_SIZE | MOUNTINFO_READONLY)))
+                continue;
+
+            do_disk_space_stats(mi, update_every);
+        }
+    }
+
+    info("DISKSPACE thread exiting");
+
+    static_thread->enabled = 0;
+    static_thread->thread = NULL;
+    pthread_exit(NULL);
+    return NULL;
+}
diff --git a/src/plugin_proc_diskspace.h b/src/plugin_proc_diskspace.h
new file mode 100644 (file)
index 0000000..dcec28f
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef NETDATA_PLUGIN_PROC_DISKSPACE_H
+#define NETDATA_PLUGIN_PROC_DISKSPACE_H
+
+extern void *proc_diskspace_main(void *ptr);
+
+#endif //NETDATA_PLUGIN_PROC_DISKSPACE_H
index 574470dc86b501c3396eed7762ab896c4bb71ead..673aa9a6dd048d5a7e82bbbf0a4958ef4c351f66 100644 (file)
@@ -7,7 +7,7 @@
 #define DISK_TYPE_CONTAINER 3
 
 #ifndef NETDATA_RELOAD_MOUNTINFO_EVERY
-#define NETDATA_RELOAD_MOUNTINFO_EVERY 10
+#define NETDATA_RELOAD_MOUNTINFO_EVERY 60
 #endif
 
 static struct disk {
@@ -39,10 +39,6 @@ static inline void mountinfo_reload(int force) {
     time_t now = now_realtime_sec();
 
     if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
-//#ifdef NETDATA_INTERNAL_CHECKS
-//        info("Reloading mountinfo");
-//#endif
-
         // mountinfo_free() can be called with NULL disk_mountinfo_root
         mountinfo_free(disk_mountinfo_root);
 
@@ -53,142 +49,6 @@ static inline void mountinfo_reload(int force) {
     }
 }
 
-
-// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
-// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
-struct mount_point_metadata {
-    int do_space;
-    int do_inodes;
-};
-
-static inline void do_disk_space_stats(struct mountinfo *mi, int update_every, usec_t dt) {
-    (void)dt;
-
-    const char *family = mi->mount_point;
-    const char *disk = mi->persistent_id;
-
-    static DICTIONARY *mount_points = NULL;
-    static NETDATA_SIMPLE_PATTERN *excluded_mountpoints = NULL;
-    int do_space, do_inodes;
-
-    if(unlikely(!mount_points)) {
-        mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
-        excluded_mountpoints = netdata_simple_pattern_list_create(config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", "/proc/ /sys/ /var/run/user/ /run/user/"), NETDATA_SIMPLE_PATTERN_MODE_PREFIX);
-    }
-
-    struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
-    if(unlikely(!m)) {
-        char var_name[4096 + 1];
-        snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", mi->mount_point);
-
-        int def_space = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
-        int def_inodes = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
-
-        if(unlikely(netdata_simple_pattern_list_matches(excluded_mountpoints, mi->mount_point))) {
-            def_space = CONFIG_ONDEMAND_NO;
-            def_inodes = CONFIG_ONDEMAND_NO;
-        }
-
-        do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
-        do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
-
-        struct mount_point_metadata mp = {
-            .do_space = do_space,
-            .do_inodes = do_inodes
-        };
-
-        dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
-    }
-    else {
-        do_space = m->do_space;
-        do_inodes = m->do_inodes;
-    }
-
-    if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
-        return;
-
-    struct statvfs buff_statvfs;
-    if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
-        error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
-        return;
-    }
-
-    // taken from get_fs_usage() found in coreutils
-    unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
-
-    fsblkcnt_t bavail         = buff_statvfs.f_bavail;
-    fsblkcnt_t btotal         = buff_statvfs.f_blocks;
-    fsblkcnt_t bavail_root    = buff_statvfs.f_bfree;
-    fsblkcnt_t breserved_root = bavail_root - bavail;
-    fsblkcnt_t bused;
-    if(likely(btotal >= bavail_root))
-        bused = btotal - bavail_root;
-    else
-        bused = bavail_root - btotal;
-
-#ifdef NETDATA_INTERNAL_CHECKS
-    if(unlikely(btotal != bavail + breserved_root + bused))
-        error("Disk block statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)btotal, (unsigned long long)bavail, (unsigned long long)breserved_root, (unsigned long long)bused);
-#endif
-
-    // --------------------------------------------------------------------------
-
-    fsfilcnt_t favail         = buff_statvfs.f_favail;
-    fsfilcnt_t ftotal         = buff_statvfs.f_files;
-    fsfilcnt_t favail_root    = buff_statvfs.f_ffree;
-    fsfilcnt_t freserved_root = favail_root - favail;
-    fsfilcnt_t fused          = ftotal - favail_root;
-
-#ifdef NETDATA_INTERNAL_CHECKS
-    if(unlikely(btotal != bavail + breserved_root + bused))
-        error("Disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused);
-#endif
-
-    // --------------------------------------------------------------------------
-
-    RRDSET *st;
-
-    if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
-        st = rrdset_find_bytype("disk_space", disk);
-        if(unlikely(!st)) {
-            char title[4096 + 1];
-            snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
-            st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
-
-            rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
-            rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
-            rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
-        }
-        else rrdset_next(st);
-
-        rrddim_set(st, "avail", (collected_number)bavail);
-        rrddim_set(st, "used", (collected_number)bused);
-        rrddim_set(st, "reserved_for_root", (collected_number)breserved_root);
-        rrdset_done(st);
-    }
-
-    // --------------------------------------------------------------------------
-
-    if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
-        st = rrdset_find_bytype("disk_inodes", disk);
-        if(unlikely(!st)) {
-            char title[4096 + 1];
-            snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
-            st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
-
-            rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
-            rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
-            rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
-        }
-        else rrdset_next(st);
-
-        rrddim_set(st, "avail", (collected_number)favail);
-        rrddim_set(st, "used", (collected_number)fused);
-        rrddim_set(st, "reserved_for_root", (collected_number)freserved_root);
-        rrdset_done(st);
-    }
-}
-
 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
     static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
     static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
@@ -325,15 +185,6 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
     return d;
 }
 
-static inline int select_positive_option(int option1, int option2) {
-    if(unlikely(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES))
-        return CONFIG_ONDEMAND_YES;
-    else if(unlikely(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND))
-        return CONFIG_ONDEMAND_ONDEMAND;
-
-    return CONFIG_ONDEMAND_NO;
-}
-
 static inline int is_major_enabled(int major) {
     static char *major_configs = NULL;
     static size_t major_size = 0;
@@ -401,17 +252,6 @@ int do_proc_diskstats(int update_every, usec_t dt) {
 
     mountinfo_reload(0);
 
-    // --------------------------------------------------------------------------
-    // disk space metrics
-
-    struct mountinfo *mi;
-    for(mi = disk_mountinfo_root; mi ;mi = mi->next) {
-        if(unlikely(mi->flags & (MOUNTINFO_IS_DUMMY|MOUNTINFO_IS_BIND|MOUNTINFO_IS_SAME_DEV|MOUNTINFO_NO_STAT|MOUNTINFO_NO_SIZE|MOUNTINFO_READONLY)))
-            continue;
-
-        do_disk_space_stats(mi, update_every, dt);
-    }
-
     // --------------------------------------------------------------------------
 
     if(unlikely(!ff)) {