@cryptotaxi247 / netdata-1 / commits / 0ff3db703

diskspace statistics are now a separate thread, to isolate the delays introduced by statvfs()

Costa Tsaousis (ktsaou) committed Jan 14, 2017 at 15:47 UTC 0ff3db703848117e59a7b2d1b9e3401348f3715e
7 files changed +238 -162
CMakeLists.txt
+1 -1
@@ -101,7 +101,7 @@ set(NETDATA_SOURCE_FILES
101 src/registry_person.c
102 src/registry_person.h
103 src/registry_machine.c
104 - 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)
104 + 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)
105
106 set(APPS_PLUGIN_SOURCE_FILES
107 src/appconfig.c
src/Makefile.am
+1
@@ -86,6 +86,7 @@ else
86 netdata_SOURCES += \
87 ipc.c ipc.h \
88 plugin_proc.c plugin_proc.h \
89 + plugin_proc_diskspace.c plugin_proc_diskspace.h \
90 proc_diskstats.c \
91 proc_interrupts.c \
92 proc_softirqs.c \
src/common.h
+1
@@ -188,6 +188,7 @@
188 #include "plugin_macos.h"
189 #else
190 #include "plugin_proc.h"
191 +#include "plugin_proc_diskspace.h"
192 #endif /* __FreeBSD__, __APPLE__*/
193
194 #include "plugin_tc.h"
src/main.c
+1
@@ -45,6 +45,7 @@ struct netdata_static_thread static_threads[] = {
45 {"macos", "plugins", "macos", 1, NULL, NULL, macos_main},
46 #else
47 {"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
48 + {"diskspace", "plugins", "diskspace", 1, NULL, NULL, proc_diskspace_main},
49 #endif /* __FreeBSD__, __APPLE__*/
50 {"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
51 {"check", "plugins", "checks", 0, NULL, NULL, checks_main},
src/plugin_proc_diskspace.c new
+227
@@ -0,0 +1,227 @@
1 +#include "common.h"
2 +
3 +#ifndef NETDATA_RELOAD_MOUNTINFO_EVERY
4 +#define NETDATA_RELOAD_MOUNTINFO_EVERY 60
5 +#endif
6 +
7 +#define DELAULT_EXLUDED_PATHS "/proc/ /sys/ /var/run/user/ /run/user/"
8 +
9 +static struct mountinfo *disk_mountinfo_root = NULL;
10 +
11 +static inline void mountinfo_reload(int force) {
12 + static time_t last_loaded = 0;
13 + time_t now = now_realtime_sec();
14 +
15 + if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
16 + // mountinfo_free() can be called with NULL disk_mountinfo_root
17 + mountinfo_free(disk_mountinfo_root);
18 +
19 + // re-read mountinfo in case something changed
20 + disk_mountinfo_root = mountinfo_read();
21 +
22 + last_loaded = now;
23 + }
24 +}
25 +
26 +// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
27 +// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
28 +struct mount_point_metadata {
29 + int do_space;
30 + int do_inodes;
31 + int update_every;
32 +};
33 +
34 +static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
35 + const char *family = mi->mount_point;
36 + const char *disk = mi->persistent_id;
37 +
38 + static DICTIONARY *mount_points = NULL;
39 + static NETDATA_SIMPLE_PATTERN *excluded_mountpoints = NULL;
40 + int do_space, do_inodes;
41 +
42 + if(unlikely(!mount_points)) {
43 + const char *s;
44 +
45 + if(config_exists("plugin:proc:/proc/diskstats", "exclude space metrics on paths") && !config_exists("plugin:proc:diskspace", "exclude space metrics on paths")) {
46 + // the config exists in the old section
47 + s = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
48 +
49 + // set it to the new section
50 + config_set("plugin:proc:diskspace", "exclude space metrics on paths", s);
51 + }
52 + else
53 + s = config_get("plugin:proc:diskspace", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS);
54 +
55 + mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
56 + excluded_mountpoints = netdata_simple_pattern_list_create(s, NETDATA_SIMPLE_PATTERN_MODE_PREFIX);
57 + }
58 +
59 + struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
60 + if(unlikely(!m)) {
61 + char var_name[4096 + 1];
62 + snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
63 +
64 + int def_space = config_get_boolean_ondemand("plugin:proc:diskspace", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
65 + int def_inodes = config_get_boolean_ondemand("plugin:proc:diskspace", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
66 +
67 + if(unlikely(netdata_simple_pattern_list_matches(excluded_mountpoints, mi->mount_point))) {
68 + def_space = CONFIG_ONDEMAND_NO;
69 + def_inodes = CONFIG_ONDEMAND_NO;
70 + }
71 +
72 + do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
73 + do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
74 +
75 + struct mount_point_metadata mp = {
76 + .do_space = do_space,
77 + .do_inodes = do_inodes,
78 + .update_every = rrd_update_every
79 + };
80 +
81 + dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
82 + }
83 + else {
84 + do_space = m->do_space;
85 + do_inodes = m->do_inodes;
86 + update_every = m->update_every;
87 + }
88 +
89 + if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
90 + return;
91 +
92 + struct statvfs buff_statvfs;
93 + if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
94 + error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
95 + return;
96 + }
97 +
98 + // taken from get_fs_usage() found in coreutils
99 + unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
100 +
101 + fsblkcnt_t bavail = buff_statvfs.f_bavail;
102 + fsblkcnt_t btotal = buff_statvfs.f_blocks;
103 + fsblkcnt_t bavail_root = buff_statvfs.f_bfree;
104 + fsblkcnt_t breserved_root = bavail_root - bavail;
105 + fsblkcnt_t bused;
106 + if(likely(btotal >= bavail_root))
107 + bused = btotal - bavail_root;
108 + else
109 + bused = bavail_root - btotal;
110 +
111 +#ifdef NETDATA_INTERNAL_CHECKS
112 + if(unlikely(btotal != bavail + breserved_root + bused))
113 + 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);
114 +#endif
115 +
116 + // --------------------------------------------------------------------------
117 +
118 + fsfilcnt_t favail = buff_statvfs.f_favail;
119 + fsfilcnt_t ftotal = buff_statvfs.f_files;
120 + fsfilcnt_t favail_root = buff_statvfs.f_ffree;
121 + fsfilcnt_t freserved_root = favail_root - favail;
122 + fsfilcnt_t fused = ftotal - favail_root;
123 +
124 +#ifdef NETDATA_INTERNAL_CHECKS
125 + if(unlikely(btotal != bavail + breserved_root + bused))
126 + 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);
127 +#endif
128 +
129 + // --------------------------------------------------------------------------
130 +
131 + RRDSET *st;
132 +
133 + if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
134 + st = rrdset_find_bytype("disk_space", disk);
135 + if(unlikely(!st)) {
136 + char title[4096 + 1];
137 + snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
138 + st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
139 +
140 + rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
141 + rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
142 + rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
143 + }
144 + else rrdset_next(st);
145 +
146 + rrddim_set(st, "avail", (collected_number)bavail);
147 + rrddim_set(st, "used", (collected_number)bused);
148 + rrddim_set(st, "reserved_for_root", (collected_number)breserved_root);
149 + rrdset_done(st);
150 + }
151 +
152 + // --------------------------------------------------------------------------
153 +
154 + if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
155 + st = rrdset_find_bytype("disk_inodes", disk);
156 + if(unlikely(!st)) {
157 + char title[4096 + 1];
158 + snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
159 + st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
160 +
161 + rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
162 + rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
163 + rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
164 + }
165 + else rrdset_next(st);
166 +
167 + rrddim_set(st, "avail", (collected_number)favail);
168 + rrddim_set(st, "used", (collected_number)fused);
169 + rrddim_set(st, "reserved_for_root", (collected_number)freserved_root);
170 + rrdset_done(st);
171 + }
172 +}
173 +
174 +void *proc_diskspace_main(void *ptr) {
175 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
176 +
177 + info("DISKSPACE thread created with task id %d", gettid());
178 +
179 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
180 + error("Cannot set pthread cancel type to DEFERRED.");
181 +
182 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
183 + error("Cannot set pthread cancel state to ENABLE.");
184 +
185 + int update_every = (int)config_get_number("plugin:proc:diskspace", "update every", rrd_update_every);
186 + if(update_every < rrd_update_every)
187 + update_every = rrd_update_every;
188 +
189 + usec_t step = update_every * USEC_PER_SEC;
190 + for(;;) {
191 + usec_t now = now_monotonic_usec();
192 + usec_t next = now - (now % step) + step;
193 +
194 + while(now < next) {
195 + sleep_usec(next - now);
196 + now = now_monotonic_usec();
197 + }
198 +
199 + if(unlikely(netdata_exit)) break;
200 +
201 + // --------------------------------------------------------------------------
202 + // this is smart enough not to reload it every time
203 +
204 + mountinfo_reload(0);
205 +
206 + // --------------------------------------------------------------------------
207 + // disk space metrics
208 +
209 + struct mountinfo *mi;
210 + for(mi = disk_mountinfo_root; mi; mi = mi->next) {
211 +
212 + if(unlikely(mi->flags &
213 + (MOUNTINFO_IS_DUMMY | MOUNTINFO_IS_BIND | MOUNTINFO_IS_SAME_DEV | MOUNTINFO_NO_STAT |
214 + MOUNTINFO_NO_SIZE | MOUNTINFO_READONLY)))
215 + continue;
216 +
217 + do_disk_space_stats(mi, update_every);
218 + }
219 + }
220 +
221 + info("DISKSPACE thread exiting");
222 +
223 + static_thread->enabled = 0;
224 + static_thread->thread = NULL;
225 + pthread_exit(NULL);
226 + return NULL;
227 +}
src/plugin_proc_diskspace.h new
+6
@@ -0,0 +1,6 @@
1 +#ifndef NETDATA_PLUGIN_PROC_DISKSPACE_H
2 +#define NETDATA_PLUGIN_PROC_DISKSPACE_H
3 +
4 +extern void *proc_diskspace_main(void *ptr);
5 +
6 +#endif //NETDATA_PLUGIN_PROC_DISKSPACE_H
src/proc_diskstats.c
+1 -161
@@ -7,7 +7,7 @@
7 #define DISK_TYPE_CONTAINER 3
8
9 #ifndef NETDATA_RELOAD_MOUNTINFO_EVERY
10 -#define NETDATA_RELOAD_MOUNTINFO_EVERY 10
10 +#define NETDATA_RELOAD_MOUNTINFO_EVERY 60
11 #endif
12
13 static struct disk {
@@ -39,10 +39,6 @@ static inline void mountinfo_reload(int force) {
39 time_t now = now_realtime_sec();
40
41 if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
42 -//#ifdef NETDATA_INTERNAL_CHECKS
43 -// info("Reloading mountinfo");
44 -//#endif
45 -
42 // mountinfo_free() can be called with NULL disk_mountinfo_root
43 mountinfo_free(disk_mountinfo_root);
44
@@ -53,142 +49,6 @@ static inline void mountinfo_reload(int force) {
49 }
50 }
51
56 -
57 -// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
58 -// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
59 -struct mount_point_metadata {
60 - int do_space;
61 - int do_inodes;
62 -};
63 -
64 -static inline void do_disk_space_stats(struct mountinfo *mi, int update_every, usec_t dt) {
65 - (void)dt;
66 -
67 - const char *family = mi->mount_point;
68 - const char *disk = mi->persistent_id;
69 -
70 - static DICTIONARY *mount_points = NULL;
71 - static NETDATA_SIMPLE_PATTERN *excluded_mountpoints = NULL;
72 - int do_space, do_inodes;
73 -
74 - if(unlikely(!mount_points)) {
75 - mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
76 - 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);
77 - }
78 -
79 - struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point);
80 - if(unlikely(!m)) {
81 - char var_name[4096 + 1];
82 - snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", mi->mount_point);
83 -
84 - int def_space = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
85 - int def_inodes = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
86 -
87 - if(unlikely(netdata_simple_pattern_list_matches(excluded_mountpoints, mi->mount_point))) {
88 - def_space = CONFIG_ONDEMAND_NO;
89 - def_inodes = CONFIG_ONDEMAND_NO;
90 - }
91 -
92 - do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
93 - do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
94 -
95 - struct mount_point_metadata mp = {
96 - .do_space = do_space,
97 - .do_inodes = do_inodes
98 - };
99 -
100 - dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata));
101 - }
102 - else {
103 - do_space = m->do_space;
104 - do_inodes = m->do_inodes;
105 - }
106 -
107 - if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO))
108 - return;
109 -
110 - struct statvfs buff_statvfs;
111 - if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
112 - error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk);
113 - return;
114 - }
115 -
116 - // taken from get_fs_usage() found in coreutils
117 - unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
118 -
119 - fsblkcnt_t bavail = buff_statvfs.f_bavail;
120 - fsblkcnt_t btotal = buff_statvfs.f_blocks;
121 - fsblkcnt_t bavail_root = buff_statvfs.f_bfree;
122 - fsblkcnt_t breserved_root = bavail_root - bavail;
123 - fsblkcnt_t bused;
124 - if(likely(btotal >= bavail_root))
125 - bused = btotal - bavail_root;
126 - else
127 - bused = bavail_root - btotal;
128 -
129 -#ifdef NETDATA_INTERNAL_CHECKS
130 - if(unlikely(btotal != bavail + breserved_root + bused))
131 - 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);
132 -#endif
133 -
134 - // --------------------------------------------------------------------------
135 -
136 - fsfilcnt_t favail = buff_statvfs.f_favail;
137 - fsfilcnt_t ftotal = buff_statvfs.f_files;
138 - fsfilcnt_t favail_root = buff_statvfs.f_ffree;
139 - fsfilcnt_t freserved_root = favail_root - favail;
140 - fsfilcnt_t fused = ftotal - favail_root;
141 -
142 -#ifdef NETDATA_INTERNAL_CHECKS
143 - if(unlikely(btotal != bavail + breserved_root + bused))
144 - 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);
145 -#endif
146 -
147 - // --------------------------------------------------------------------------
148 -
149 - RRDSET *st;
150 -
151 - if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
152 - st = rrdset_find_bytype("disk_space", disk);
153 - if(unlikely(!st)) {
154 - char title[4096 + 1];
155 - snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source);
156 - st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
157 -
158 - rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
159 - rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
160 - rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
161 - }
162 - else rrdset_next(st);
163 -
164 - rrddim_set(st, "avail", (collected_number)bavail);
165 - rrddim_set(st, "used", (collected_number)bused);
166 - rrddim_set(st, "reserved_for_root", (collected_number)breserved_root);
167 - rrdset_done(st);
168 - }
169 -
170 - // --------------------------------------------------------------------------
171 -
172 - if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
173 - st = rrdset_find_bytype("disk_inodes", disk);
174 - if(unlikely(!st)) {
175 - char title[4096 + 1];
176 - snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source);
177 - st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
178 -
179 - rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
180 - rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
181 - rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
182 - }
183 - else rrdset_next(st);
184 -
185 - rrddim_set(st, "avail", (collected_number)favail);
186 - rrddim_set(st, "used", (collected_number)fused);
187 - rrddim_set(st, "reserved_for_root", (collected_number)freserved_root);
188 - rrdset_done(st);
189 - }
190 -}
191 -
52 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
53 static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
54 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
185 return d;
186 }
187
328 -static inline int select_positive_option(int option1, int option2) {
329 - if(unlikely(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES))
330 - return CONFIG_ONDEMAND_YES;
331 - else if(unlikely(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND))
332 - return CONFIG_ONDEMAND_ONDEMAND;
333 -
334 - return CONFIG_ONDEMAND_NO;
335 -}
336 -
188 static inline int is_major_enabled(int major) {
189 static char *major_configs = NULL;
190 static size_t major_size = 0;
@@ -401,17 +252,6 @@ int do_proc_diskstats(int update_every, usec_t dt) {
252
253 mountinfo_reload(0);
254
404 - // --------------------------------------------------------------------------
405 - // disk space metrics
406 -
407 - struct mountinfo *mi;
408 - for(mi = disk_mountinfo_root; mi ;mi = mi->next) {
409 - if(unlikely(mi->flags & (MOUNTINFO_IS_DUMMY|MOUNTINFO_IS_BIND|MOUNTINFO_IS_SAME_DEV|MOUNTINFO_NO_STAT|MOUNTINFO_NO_SIZE|MOUNTINFO_READONLY)))
410 - continue;
411 -
412 - do_disk_space_stats(mi, update_every, dt);
413 - }
414 -
255 // --------------------------------------------------------------------------
256
257 if(unlikely(!ff)) {