]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #431 from ktsaou/master
authorCosta Tsaousis <costa@tsaousis.gr>
Sat, 21 May 2016 16:23:05 +0000 (19:23 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Sat, 21 May 2016 16:23:05 +0000 (19:23 +0300)
optimizations

src/appconfig.c
src/dictionary.c
src/dictionary.h
src/global_statistics.c
src/global_statistics.h
src/plugin_proc.c
src/proc_diskstats.c
src/url.c
src/url.h
src/web_client.c
src/web_client.h

index 0ec4cad322575ff0852ae189fd87f9bd0e850b8c..415b475d7ec0eca20559981f14200823ee8e8c4f 100644 (file)
@@ -242,8 +242,8 @@ int config_get_boolean(const char *section, const char *name, int value)
        s = config_get(section, name, s);
        if(!s) return value;
 
-       if(!strcmp(s, "yes")) return 1;
-       else return 0;
+       if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
+       return 0;
 }
 
 int config_get_boolean_ondemand(const char *section, const char *name, int value)
@@ -251,7 +251,7 @@ int config_get_boolean_ondemand(const char *section, const char *name, int value
        char *s;
 
        if(value == CONFIG_ONDEMAND_ONDEMAND)
-               s = "on demand";
+               s = "auto";
 
        else if(value == CONFIG_ONDEMAND_NO)
                s = "no";
@@ -266,7 +266,7 @@ int config_get_boolean_ondemand(const char *section, const char *name, int value
                return CONFIG_ONDEMAND_YES;
        else if(!strcmp(s, "no"))
                return CONFIG_ONDEMAND_NO;
-       else if(!strcmp(s, "on demand"))
+       else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
                return CONFIG_ONDEMAND_ONDEMAND;
 
        return value;
index 1543f4d0e7334bce5ad63e2b5469e5b47b0dffb8..d3576412b5dc1264a1068db2eeb1c1adca7a0542 100644 (file)
@@ -46,15 +46,15 @@ static int name_value_compare(void* a, void* b) {
        else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
 }
 
-#define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
-#define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
+#define dictionary_name_value_index_add_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
+#define dictionary_name_value_index_del_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
 
 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
        NAME_VALUE tmp;
        tmp.hash = (hash)?hash:simple_hash(name);
        tmp.name = (char *)name;
 
-       dict->searches++;
+       NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict);
        return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp);
 }
 
@@ -89,7 +89,7 @@ static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const c
 
        // index it
        dictionary_name_value_index_add_nolock(dict, nv);
-       dict->entries++;
+       NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict);
 
        return nv;
 }
@@ -99,7 +99,7 @@ static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *n
 
        dictionary_name_value_index_del_nolock(dict, nv);
 
-       dict->entries--;
+       NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict);
 
        if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
                debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
index 575f2827105c443644bfe6349769383bab58db47..fe44d8146093f3c3e2fe0dc472b04880b14bbce1 100644 (file)
@@ -21,14 +21,30 @@ typedef struct dictionary {
 
        uint8_t flags;
 
+#ifdef NETDATA_DICTIONARY_WITH_STATISTICS
        unsigned long long inserts;
        unsigned long long deletes;
        unsigned long long searches;
        unsigned long long entries;
+#endif /* NETDATA_DICTIONARY_WITH_STATISTICS */
 
        pthread_rwlock_t rwlock;
 } DICTIONARY;
 
+#ifdef NETDATA_DICTIONARY_WITH_STATISTICS
+#define NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict) (dict)->inserts++
+#define NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict) (dict)->deletes++
+#define NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict) (dict)->searches++
+#define NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict) (dict)->entries++
+#define NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict) (dict)->entries--
+#else /* NETDATA_DICTIONARY_WITH_STATISTICS */
+#define NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict)
+#define NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict)
+#define NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict)
+#define NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict)
+#define NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict)
+#endif /* NETDATA_DICTIONARY_WITH_STATISTICS */
+
 #define DICTIONARY_FLAG_DEFAULT                                        0x00000000
 #define DICTIONARY_FLAG_SINGLE_THREADED                        0x00000001
 #define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE  0x00000002
index d4a04efd2d067aa32c7bf6d085a998e3522c449c..d813f66c9b9d4d31838a6d7fb44f664cdd412b9a 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "global_statistics.h"
 
-struct global_statistics global_statistics = { 0ULL, 0ULL, 0ULL, 0ULL };
+struct global_statistics global_statistics = { 0, 0ULL, 0ULL, 0ULL, 0ULL};
 
 pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
 
index ce3c3490e95c30e179a4e26a851e80bd9430cb0b..b618191656fc3d9537002ded68e4e812da8836f1 100644 (file)
@@ -5,11 +5,11 @@
 // global statistics
 
 struct global_statistics {
-       unsigned long long connected_clients;
-       unsigned long long web_requests;
-       unsigned long long bytes_received;
-       unsigned long long bytes_sent;
-
+       unsigned long volatile connected_clients;
+       unsigned long long volatile web_requests;
+       unsigned long long volatile web_usec;
+       unsigned long long volatile bytes_received;
+       unsigned long long volatile bytes_sent;
 };
 
 extern struct global_statistics global_statistics;
index a147d971f8128609d1e9416309ef7e35138e8765..5ecd7b9e459a3e7e1daa4114bb63e3f626930061 100644 (file)
@@ -18,7 +18,8 @@
 
 void *proc_main(void *ptr)
 {
-       if(ptr) { ; }
+       static unsigned long long old_web_requests = 0, old_web_usec = 0;
+       (void)ptr;
 
        info("PROC Plugin thread created with task id %d", gettid());
 
@@ -77,7 +78,7 @@ void *proc_main(void *ptr)
        unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
        unsigned long long sunow;
 
-       RRDSET *stcpu = NULL, *stcpu_thread = NULL, *stclients = NULL, *streqs = NULL, *stbytes = NULL;
+       RRDSET *stcpu = NULL, *stcpu_thread = NULL, *stclients = NULL, *streqs = NULL, *stbytes = NULL, *stduration = NULL;
 
        for(;1;) {
                if(unlikely(netdata_exit)) break;
@@ -310,6 +311,30 @@ void *proc_main(void *ptr)
 
                        // ----------------------------------------------------------------
 
+                       if(!stduration) stduration = rrdset_find("netdata.response_time");
+                       if(!stduration) {
+                               stduration = rrdset_create("netdata", "response_time", NULL, "netdata", NULL, "NetData Average API Response Time", "ms/request", 130400, rrd_update_every, RRDSET_TYPE_LINE);
+
+                               rrddim_add(stduration, "response_time", "response time",  1, 1000, RRDDIM_ABSOLUTE);
+                       }
+                       else rrdset_next(stduration);
+
+                       unsigned long long gweb_usec     = global_statistics.web_usec;
+                       unsigned long long gweb_requests = global_statistics.web_requests;
+
+                       unsigned long long web_usec     = gweb_usec     - old_web_usec;
+                       unsigned long long web_requests = gweb_requests - old_web_requests;
+
+                       old_web_usec     = gweb_usec;
+                       old_web_requests = gweb_requests;
+
+                       if(!web_requests) web_requests = 1;
+
+                       rrddim_set(stduration, "response_time", web_usec / web_requests);
+                       rrdset_done(stduration);
+
+                       // ----------------------------------------------------------------
+
                        registry_statistics();
                }
        }
index fc835800e6e73226a368660875e63fd2a0371449..78c8092dfe769f769e24bd90d67f9f9c8b21da52 100644 (file)
 #define DISK_TYPE_PARTITION 2
 #define DISK_TYPE_CONTAINER 3
 
-struct disk {
+static struct disk {
+       char *disk;                             // the name of the disk (sda, sdb, etc)
        unsigned long major;
        unsigned long minor;
+       int sector_size;
        int type;
        char *mount_point;
+
+       // disk options caching
+       int configured;
+       int do_io;
+       int do_ops;
+       int do_mops;
+       int do_iotime;
+       int do_qops;
+       int do_util;
+       int do_backlog;
+       int do_space;
+       int do_inodes;
+
        struct disk *next;
 } *disk_root = NULL;
 
-struct disk *get_disk(unsigned long major, unsigned long minor) {
+static struct mountinfo *disk_mountinfo_root = NULL;
+
+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] = "";
        static char path_find_block_device[FILENAME_MAX + 1] = "";
-       static struct mountinfo *mountinfo_root = NULL;
        struct disk *d;
 
        // search for it in our RAM list.
@@ -52,20 +70,17 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
        if(likely(d))
                return d;
 
-       if(unlikely(!path_find_block_device[0])) {
-               char dirname[FILENAME_MAX + 1];
-               snprintfz(dirname, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
-               snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", dirname));
-       }
-
        // not found
        // create a new disk structure
        d = (struct disk *)malloc(sizeof(struct disk));
        if(!d) fatal("Cannot allocate memory for struct disk in proc_diskstats.");
 
+       d->disk = strdup(disk);
        d->major = major;
        d->minor = minor;
        d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
+       d->configured = 0;
+       d->sector_size = 512; // the default, will be changed below
        d->next = NULL;
 
        // append it to the list
@@ -80,9 +95,16 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
        // ------------------------------------------------------------------------
        // find the type of the device
 
+       char buffer[FILENAME_MAX + 1];
+
+       // get the default path for finding info about the block device
+       if(unlikely(!path_find_block_device[0])) {
+               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
+               snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
+       }
+
        // find if it is a partition
        // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
-       char buffer[FILENAME_MAX + 1];
        snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
        if(access(buffer, R_OK) == 0) {
                d->type = DISK_TYPE_PARTITION;
@@ -92,13 +114,15 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
                snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
                DIR *dirp = opendir(buffer);    
                if (dirp != NULL) {
-               struct dirent *dp;
+                       struct dirent *dp;
                        while( (dp = readdir(dirp)) ) {
                                // . and .. are also files in empty folders.
                                if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
                                        continue;
                                }
+
                                d->type = DISK_TYPE_CONTAINER;
+
                                // Stop the loop after we found one file.
                                break;
                        }
@@ -110,17 +134,17 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
        // ------------------------------------------------------------------------
        // check if we can find its mount point
 
-       // mountinfo_find() can be called with NULL mountinfo_root
-       struct mountinfo *mi = mountinfo_find(mountinfo_root, d->major, d->minor);
+       // mountinfo_find() can be called with NULL disk_mountinfo_root
+       struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
        if(unlikely(!mi)) {
-               // mountinfo_free() can be called with NULL mountinfo_root
-               mountinfo_free(mountinfo_root);
+               // mountinfo_free() can be called with NULL disk_mountinfo_root
+               mountinfo_free(disk_mountinfo_root);
 
                // re-read mountinfo in case something changed
-               mountinfo_root = mountinfo_read();
+               disk_mountinfo_root = mountinfo_read();
 
                // search again for this disk
-               mi = mountinfo_find(mountinfo_root, d->major, d->minor);
+               mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
        }
 
        if(mi)
@@ -129,36 +153,106 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
        else
                d->mount_point = NULL;
 
+       // ------------------------------------------------------------------------
+       // find the disk sector size
+
+       if(!path_to_get_hw_sector_size[0]) {
+               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
+               snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
+       }
+       if(!path_to_get_hw_sector_size_partitions[0]) {
+               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
+               snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
+       }
+
+       {
+               char tf[FILENAME_MAX + 1], *t;
+               strncpyz(tf, d->disk, FILENAME_MAX);
+
+               // replace all / with !
+               for(t = tf; *t ;t++)
+                       if(*t == '/') *t = '!';
+
+               if(d->type == DISK_TYPE_PARTITION)
+                       snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf);
+               else
+                       snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf);
+
+               FILE *fpss = fopen(buffer, "r");
+               if(fpss) {
+                       char buffer2[1024 + 1];
+                       char *tmp = fgets(buffer2, 1024, fpss);
+
+                       if(tmp) {
+                               d->sector_size = atoi(tmp);
+                               if(d->sector_size <= 0) {
+                                       error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->disk, buffer);
+                                       d->sector_size = 512;
+                               }
+                       }
+                       else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->disk, buffer);
+
+                       fclose(fpss);
+               }
+               else error("Cannot read sector size for device %s from %s. Assuming 512.", d->disk, buffer);
+       }
+
        return d;
 }
 
+static inline int select_positive_option(int option1, int option2) {
+       if(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES)
+               return CONFIG_ONDEMAND_YES;
+       else if(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND)
+               return CONFIG_ONDEMAND_ONDEMAND;
+
+       return CONFIG_ONDEMAND_NO;
+}
+
 int do_proc_diskstats(int update_every, unsigned long long dt) {
        static procfile *ff = NULL;
-       static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
-       static int enable_autodetection;
-       static int enable_physical_disks, enable_virtual_disks, enable_partitions, enable_mountpoints, enable_virtual_mountpoints, enable_space_metrics;
-       static int do_io, do_ops, do_mops, do_iotime, do_qops, do_util, do_backlog, do_space, do_inodes;
        static struct statvfs buff_statvfs;
        static struct stat buff_stat;
-
-       enable_autodetection = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
-
-       enable_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", CONFIG_ONDEMAND_ONDEMAND);
-       enable_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", CONFIG_ONDEMAND_NO);
-       enable_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", CONFIG_ONDEMAND_NO);
-       enable_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", CONFIG_ONDEMAND_NO);
-       enable_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", CONFIG_ONDEMAND_ONDEMAND);
-       enable_space_metrics = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", CONFIG_ONDEMAND_ONDEMAND);
-
-       do_io      = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_ops     = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_mops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_iotime  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_qops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_util    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_space   = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
-       do_inodes  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
+       static int      global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
+                               global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
+                               global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
+                               global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
+                               global_enable_performance_for_mountpoints = CONFIG_ONDEMAND_NO,
+                               global_enable_performance_for_virtual_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
+                               global_enable_space_for_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_io = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_util = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_space = CONFIG_ONDEMAND_ONDEMAND,
+                               global_do_inodes = CONFIG_ONDEMAND_ONDEMAND,
+                               globals_initialized = 0;
+
+       if(unlikely(!globals_initialized)) {
+               global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
+
+               global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
+               global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
+               global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
+               global_enable_performance_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", global_enable_performance_for_mountpoints);
+               global_enable_performance_for_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", global_enable_performance_for_virtual_mountpoints);
+               global_enable_space_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", global_enable_space_for_mountpoints);
+
+               global_do_io      = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
+               global_do_ops     = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
+               global_do_mops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
+               global_do_iotime  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
+               global_do_qops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
+               global_do_util    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
+               global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
+               global_do_space   = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", global_do_space);
+               global_do_inodes  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", global_do_inodes);
+
+               globals_initialized = 1;
+       }
 
        if(!ff) {
                char filename[FILENAME_MAX + 1];
@@ -167,12 +261,6 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
        }
        if(!ff) return 1;
 
-       if(!path_to_get_hw_sector_size[0]) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
-               snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", filename));
-       }
-
        ff = procfile_readall(ff);
        if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
@@ -182,6 +270,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
        for(l = 0; l < lines ;l++) {
                // --------------------------------------------------------------------------
                // Read parameters
+
                char *disk;
                unsigned long long      major = 0, minor = 0,
                                                        reads = 0,  mreads = 0,  readsectors = 0,  readms = 0,
@@ -241,331 +330,393 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
                // I/O completion time and the backlog that may be accumulating.
                backlog_ms              = strtoull(procfile_lineword(ff, l, 13), NULL, 10);     // rq_ticks
 
+
                // --------------------------------------------------------------------------
                // remove slashes from disk names
                char *s;
-               for(s = disk; *s ;s++) if(*s == '/') *s = '_';
-               struct disk *d = get_disk(major, minor);
-               // Find mount point and family
-               char *mount_point = d->mount_point;
+               for(s = disk; *s ;s++)
+                       if(*s == '/') *s = '_';
+
+               // --------------------------------------------------------------------------
+               // get a disk structure for the disk
+
+               struct disk *d = get_disk(major, minor, disk);
+
+
+               // --------------------------------------------------------------------------
+               // Set its family based on mount point
+
                char *family = d->mount_point;
                if(!family) family = disk;
 
+
                // --------------------------------------------------------------------------
-               // Check if device is enabled by autodetection or config
-               int def_enable = -1;
-               char var_name[4096 + 1];
-               snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
-
-               if(def_enable == -1) def_enable = config_get_boolean_ondemand(var_name, "enable", CONFIG_ONDEMAND_ONDEMAND);
-               if(def_enable == CONFIG_ONDEMAND_NO) continue;
-
-               int def_performance = CONFIG_ONDEMAND_NO, def_space = CONFIG_ONDEMAND_NO;
-               if(enable_autodetection)  {
-                       if(enable_physical_disks && (d->type == DISK_TYPE_PHYSICAL)) {
-                               def_performance = enable_physical_disks;
-                       } else if(enable_virtual_disks && (d->type == DISK_TYPE_CONTAINER)) {
-                               def_performance = enable_virtual_disks;
-                       } else if(enable_partitions && (d->type == DISK_TYPE_PARTITION)) {
-                               def_performance = enable_partitions;
-                       } else if(enable_virtual_mountpoints && (d->type == DISK_TYPE_CONTAINER) && (d->mount_point != NULL)) {
-                               def_performance = enable_virtual_mountpoints;
-                       } else if(enable_mountpoints && (d->mount_point != NULL)) {
-                               def_performance = enable_mountpoints;
+               // Check the configuration for the device
+
+               if(unlikely(!d->configured)) {
+                       char var_name[4096 + 1];
+                       snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
+
+                       int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
+                       if(def_enable == CONFIG_ONDEMAND_NO) {
+                               // the user does not want any metrics for this disk
+                               d->do_io = CONFIG_ONDEMAND_NO;
+                               d->do_ops = CONFIG_ONDEMAND_NO;
+                               d->do_mops = CONFIG_ONDEMAND_NO;
+                               d->do_iotime = CONFIG_ONDEMAND_NO;
+                               d->do_qops = CONFIG_ONDEMAND_NO;
+                               d->do_util = CONFIG_ONDEMAND_NO;
+                               d->do_backlog = CONFIG_ONDEMAND_NO;
+                               d->do_space = CONFIG_ONDEMAND_NO;
+                               d->do_inodes = CONFIG_ONDEMAND_NO;
                        }
+                       else {
+                               // this disk is enabled
+                               // check its direct settings
+
+                               int def_performance = CONFIG_ONDEMAND_ONDEMAND;
+                               int def_space = (d->mount_point)?CONFIG_ONDEMAND_ONDEMAND:CONFIG_ONDEMAND_NO;
+
+                               // since this is 'on demand' we can figure the performance settings
+                               // based on the type of disk
+
+                               switch(d->type) {
+                                       case DISK_TYPE_PHYSICAL:
+                                               def_performance = global_enable_performance_for_physical_disks;
+                                               break;
 
-                       if(enable_space_metrics && (d->mount_point != NULL)) {
-                               def_space = enable_space_metrics;
+                                       case DISK_TYPE_PARTITION:
+                                               def_performance = global_enable_performance_for_partitions;
+                                               break;
+
+                                       case DISK_TYPE_CONTAINER:
+                                               def_performance = global_enable_performance_for_virtual_disks;
+
+                                               if(d->mount_point)
+                                                       def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
+
+                                               break;
+                               }
+
+                               if(d->mount_point)
+                                       def_performance = select_positive_option(def_performance, global_enable_performance_for_mountpoints);
+
+                               // ------------------------------------------------------------
+                               // now we have def_performance and def_space
+                               // to work further
+
+                               // def_performance
+                               // check the user configuration (this will also show our 'on demand' decision)
+                               def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
+
+                               int ddo_io = CONFIG_ONDEMAND_NO,
+                                       ddo_ops = CONFIG_ONDEMAND_NO,
+                                       ddo_mops = CONFIG_ONDEMAND_NO,
+                                       ddo_iotime = CONFIG_ONDEMAND_NO,
+                                       ddo_qops = CONFIG_ONDEMAND_NO,
+                                       ddo_util = CONFIG_ONDEMAND_NO,
+                                       ddo_backlog = CONFIG_ONDEMAND_NO;
+
+                               // we enable individual performance charts only when def_performance is not disabled
+                               if(def_performance != CONFIG_ONDEMAND_NO) {
+                                       ddo_io = global_do_io,
+                                       ddo_ops = global_do_ops,
+                                       ddo_mops = global_do_mops,
+                                       ddo_iotime = global_do_iotime,
+                                       ddo_qops = global_do_qops,
+                                       ddo_util = global_do_util,
+                                       ddo_backlog = global_do_backlog;
+                               }
+
+                               d->do_io      = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
+                               d->do_ops     = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
+                               d->do_mops    = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
+                               d->do_iotime  = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
+                               d->do_qops    = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
+                               d->do_util    = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
+                               d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
+
+                               // def_space
+                               if(d->mount_point) {
+                                       // check the user configuration (this will also show our 'on demand' decision)
+                                       def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
+
+                                       int ddo_space = def_space,
+                                               ddo_inodes = def_space;
+
+                                       d->do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
+                                       d->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
+                               }
+                               else {
+                                       // don't show settings for this disk
+                                       d->do_space = CONFIG_ONDEMAND_NO;
+                                       d->do_inodes = CONFIG_ONDEMAND_NO;
+                               }
                        }
+
+                       d->configured = 1;
                }
 
                RRDSET *st;
 
                // --------------------------------------------------------------------------
                // Do performance metrics
-               def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
-               if( (def_performance == CONFIG_ONDEMAND_YES) || (def_performance == CONFIG_ONDEMAND_ONDEMAND && reads && writes) ) {
-                       int ddo_io = do_io, ddo_ops = do_ops, ddo_mops = do_mops, ddo_iotime = do_iotime, ddo_qops = do_qops, ddo_util = do_util, ddo_backlog = do_backlog;
-
-                       ddo_io          = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
-                       ddo_ops         = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
-                       ddo_mops        = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
-                       ddo_iotime      = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
-                       ddo_qops        = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
-                       ddo_util        = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
-                       ddo_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
-
-                       // by default, do not add charts that do not have values
-                       if(ddo_io == CONFIG_ONDEMAND_ONDEMAND && !reads && !writes) ddo_io = 0;
-                       if(ddo_mops == CONFIG_ONDEMAND_ONDEMAND && mreads == 0 && mwrites == 0) ddo_mops = 0;
-                       if(ddo_iotime == CONFIG_ONDEMAND_ONDEMAND && readms == 0 && writems == 0) ddo_iotime = 0;
-                       if(ddo_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms == 0) ddo_util = 0;
-                       if(ddo_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms == 0) ddo_backlog = 0;
-                       if(ddo_qops == CONFIG_ONDEMAND_ONDEMAND && backlog_ms == 0) ddo_qops = 0;
-
-                       // for absolute values, we need to switch the setting to 'yes'
-                       // to allow it refresh from now on
-                       if(ddo_qops == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "queued operations", "yes");
-
-                       // --------------------------------------------------------------------
-                       int sector_size = 512;
-                       if(ddo_io) {
-                               st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
-                               if(!st) {
-                                       char tf[FILENAME_MAX + 1], *t;
-                                       char ssfilename[FILENAME_MAX + 1];
 
-                                       strncpyz(tf, disk, FILENAME_MAX);
+               if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
+                       d->do_io = CONFIG_ONDEMAND_YES;
 
-                                       // replace all / with !
-                                       while((t = strchr(tf, '/'))) *t = '!';
+                       st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
+                       if(!st) {
+                               st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
 
-                                       snprintfz(ssfilename, FILENAME_MAX, path_to_get_hw_sector_size, tf);
-                                       FILE *fpss = fopen(ssfilename, "r");
-                                       if(fpss) {
-                                               char ssbuffer[1025];
-                                               char *tmp = fgets(ssbuffer, 1024, fpss);
+                               rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
+                               rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
+                       }
+                       else rrdset_next_usec(st, dt);
 
-                                               if(tmp) {
-                                                       sector_size = atoi(tmp);
-                                                       if(sector_size <= 0) {
-                                                               error("Invalid sector size %d for device %s in %s. Assuming 512.", sector_size, disk, ssfilename);
-                                                               sector_size = 512;
-                                                       }
-                                               }
-                                               else error("Cannot read data for sector size for device %s from %s. Assuming 512.", disk, ssfilename);
+                       last_readsectors  = rrddim_set(st, "reads", readsectors);
+                       last_writesectors = rrddim_set(st, "writes", writesectors);
+                       rrdset_done(st);
+               }
 
-                                               fclose(fpss);
-                                       }
-                                       else error("Cannot read sector size for device %s from %s. Assuming 512.", disk, ssfilename);
+               // --------------------------------------------------------------------
 
-                                       st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+               if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
+                       d->do_ops = CONFIG_ONDEMAND_YES;
 
-                                       rrddim_add(st, "reads", NULL, sector_size, 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "writes", NULL, sector_size * -1, 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next_usec(st, dt);
+                       st = rrdset_find_bytype("disk_ops", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
+                               st->isdetail = 1;
 
-                               last_readsectors  = rrddim_set(st, "reads", readsectors);
-                               last_writesectors = rrddim_set(st, "writes", writesectors);
-                               rrdset_done(st);
+                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
                        }
+                       else rrdset_next_usec(st, dt);
 
-                       // --------------------------------------------------------------------
-                       if(ddo_ops) {
-                               st = rrdset_find_bytype("disk_ops", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
+                       last_reads  = rrddim_set(st, "reads", reads);
+                       last_writes = rrddim_set(st, "writes", writes);
+                       rrdset_done(st);
+               }
 
-                                       rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next_usec(st, dt);
+               // --------------------------------------------------------------------
 
-                               last_reads  = rrddim_set(st, "reads", reads);
-                               last_writes = rrddim_set(st, "writes", writes);
-                               rrdset_done(st);
+               if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
+                       d->do_qops = CONFIG_ONDEMAND_YES;
+
+                       st = rrdset_find_bytype("disk_qops", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
+                               st->isdetail = 1;
+
+                               rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
                        }
+                       else rrdset_next_usec(st, dt);
 
-                       // --------------------------------------------------------------------
-                       if(ddo_qops) {
-                               st = rrdset_find_bytype("disk_qops", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
+                       rrddim_set(st, "operations", queued_ios);
+                       rrdset_done(st);
+               }
 
-                                       rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next_usec(st, dt);
+               // --------------------------------------------------------------------
 
-                               rrddim_set(st, "operations", queued_ios);
-                               rrdset_done(st);
+               if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
+                       d->do_backlog = CONFIG_ONDEMAND_YES;
+
+                       st = rrdset_find_bytype("disk_backlog", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
+                               st->isdetail = 1;
+
+                               rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
                        }
+                       else rrdset_next_usec(st, dt);
 
-                       // --------------------------------------------------------------------
-                       if(ddo_backlog) {
-                               st = rrdset_find_bytype("disk_backlog", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
-                                       st->isdetail = 1;
+                       rrddim_set(st, "backlog", backlog_ms);
+                       rrdset_done(st);
+               }
 
-                                       rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next_usec(st, dt);
+               // --------------------------------------------------------------------
 
-                               rrddim_set(st, "backlog", backlog_ms);
-                               rrdset_done(st);
+               if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
+                       d->do_util = CONFIG_ONDEMAND_YES;
+
+                       st = rrdset_find_bytype("disk_util", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
+                               st->isdetail = 1;
+
+                               rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
                        }
+                       else rrdset_next_usec(st, dt);
+
+                       last_busy_ms = rrddim_set(st, "utilization", busy_ms);
+                       rrdset_done(st);
+               }
+
+               // --------------------------------------------------------------------
 
-                       // --------------------------------------------------------------------
-                       if(ddo_util) {
-                               st = rrdset_find_bytype("disk_util", disk);
+               if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
+                       d->do_mops = CONFIG_ONDEMAND_YES;
+
+                       st = rrdset_find_bytype("disk_mops", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
+                               st->isdetail = 1;
+
+                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                       }
+                       else rrdset_next_usec(st, dt);
+
+                       rrddim_set(st, "reads", mreads);
+                       rrddim_set(st, "writes", mwrites);
+                       rrdset_done(st);
+               }
+
+               // --------------------------------------------------------------------
+
+               if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
+                       d->do_iotime = CONFIG_ONDEMAND_YES;
+
+                       st = rrdset_find_bytype("disk_iotime", disk);
+                       if(!st) {
+                               st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
+                               st->isdetail = 1;
+
+                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                       }
+                       else rrdset_next_usec(st, dt);
+
+                       last_readms  = rrddim_set(st, "reads", readms);
+                       last_writems = rrddim_set(st, "writes", writems);
+                       rrdset_done(st);
+               }
+
+               // --------------------------------------------------------------------
+               // calculate differential charts
+               // only if this is not the first time we run
+
+               if(dt) {
+                       if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
+                               (d->do_ops    == CONFIG_ONDEMAND_YES || (d->do_ops    == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                               st = rrdset_find_bytype("disk_await", disk);
                                if(!st) {
-                                       st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
+                                       st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
                                        st->isdetail = 1;
 
-                                       rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
+                                       rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                                       rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
                                }
                                else rrdset_next_usec(st, dt);
 
-                               last_busy_ms = rrddim_set(st, "utilization", busy_ms);
+                               rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
+                               rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
                                rrdset_done(st);
                        }
 
-                       // --------------------------------------------------------------------
-                       if(ddo_mops) {
-                               st = rrdset_find_bytype("disk_mops", disk);
+                       if( (d->do_io  == CONFIG_ONDEMAND_YES || (d->do_io  == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
+                               (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                               st = rrdset_find_bytype("disk_avgsz", disk);
                                if(!st) {
-                                       st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
+                                       st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
                                        st->isdetail = 1;
 
-                                       rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                                       rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
+                                       rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
                                }
                                else rrdset_next_usec(st, dt);
 
-                               rrddim_set(st, "reads", mreads);
-                               rrddim_set(st, "writes", mwrites);
+                               rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
+                               rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
                                rrdset_done(st);
                        }
 
-                       // --------------------------------------------------------------------
-                       if(ddo_iotime) {
-                               st = rrdset_find_bytype("disk_iotime", disk);
+                       if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
+                               (d->do_ops  == CONFIG_ONDEMAND_YES || (d->do_ops  == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                               st = rrdset_find_bytype("disk_svctm", disk);
                                if(!st) {
-                                       st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
+                                       st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
                                        st->isdetail = 1;
 
-                                       rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                                       rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
                                }
                                else rrdset_next_usec(st, dt);
 
-                               last_readms  = rrddim_set(st, "reads", readms);
-                               last_writems = rrddim_set(st, "writes", writems);
+                               rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
                                rrdset_done(st);
                        }
+               }
 
-                       // --------------------------------------------------------------------
-                       // calculate differential charts
-                       // only if this is not the first time we run
-                       if(dt) {
-                               if(ddo_iotime && ddo_ops) {
-                                       st = rrdset_find_bytype("disk_await", disk);
-                                       if(!st) {
-                                               st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
-                                               st->isdetail = 1;
-
-                                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
-                                       }
-                                       else rrdset_next_usec(st, dt);
+               // --------------------------------------------------------------------------
+               // space metrics
 
-                                       rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
-                                       rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
-                                       rrdset_done(st);
-                               }
+               if(d->mount_point && (d->do_space || d->do_inodes) ) {
+                       // collect space metrics using statvfs
 
-                               if(ddo_io && ddo_ops) {
-                                       st = rrdset_find_bytype("disk_avgsz", disk);
-                                       if(!st) {
-                                               st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
-                                               st->isdetail = 1;
+                       if (statvfs(d->mount_point, &buff_statvfs) < 0)
+                               error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
+                       else {
+                               space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
+                               space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
+                               space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
 
-                                               rrddim_add(st, "reads", NULL, sector_size, 1024, RRDDIM_ABSOLUTE);
-                                               rrddim_add(st, "writes", NULL, -sector_size, 1024, RRDDIM_ABSOLUTE);
-                                       }
-                                       else rrdset_next_usec(st, dt);
+                               inodes_avail = buff_statvfs.f_favail;
+                               inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
+                               inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
 
-                                       rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
-                                       rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
-                                       rrdset_done(st);
-                               }
+                               // verify we collected the metrics for the right disk.
+                               // if not the mountpoint has changed.
 
-                               if(ddo_util && ddo_ops) {
-                                       st = rrdset_find_bytype("disk_svctm", disk);
-                                       if(!st) {
-                                               st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
-                                               st->isdetail = 1;
+                               if(stat(d->mount_point, &buff_stat) == -1)
+                                       error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
+                               else {
+                                       if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
 
-                                               rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                       }
-                                       else rrdset_next_usec(st, dt);
+                                               // --------------------------------------------------------------------------
 
-                                       rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
-                                       rrdset_done(st);
-                               }
-                       }
-               }
+                                               if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
+                                                       st = rrdset_find_bytype("disk_space", disk);
+                                                       if(!st) {
+                                                               st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
+                                                               st->isdetail = 1;
 
-               // --------------------------------------------------------------------------
-               // Do space metrics
-               def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);           
-               if(def_space != CONFIG_ONDEMAND_NO) {
-                       int ddo_space = do_space, ddo_inodes = do_inodes;
-
-                       ddo_space = config_get_boolean_ondemand(var_name, "space", ddo_space);
-                       ddo_inodes = config_get_boolean_ondemand(var_name, "inodes", ddo_space);
-                       if(mount_point && (ddo_space || ddo_inodes) ) {
-                               // collect space metrics using statvfs
-                               if (statvfs(mount_point, &buff_statvfs) < 0) {
-                                       error("Failed checking disk space usage of %s", family);
-                               } else {
-                                       // verify we collected the metrics for the right disk.
-                                       // if not the mountpoint has changed.
-                                       if(stat(mount_point, &buff_stat) == -1) {
-                                               error("Failed to call stat for %s", family);
-                                       } else {
-                                               if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor)
-                                               {
-                                                       if(ddo_space) {
-                                                               space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
-                                                               space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
-                                                               space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
-
-                                                               st = rrdset_find_bytype("disk_space", disk);
-                                                               if(!st) {
-                                                                       st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
-                                                                       st->isdetail = 1;
-
-                                                                       rrddim_add(st, "avail", NULL, 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
-                                                                       rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
-                                                                       rrddim_add(st, "used" , NULL, 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
-                                                               }
-                                                               else rrdset_next_usec(st, dt);
-
-                                                               rrddim_set(st, "avail", space_avail);
-                                                               rrddim_set(st, "reserved_for_root", space_avail_root);
-                                                               rrddim_set(st, "used", space_used);
-                                                               rrdset_done(st);
+                                                               rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
+                                                               rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
+                                                               rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
                                                        }
-                                                       if(ddo_inodes) {
-                                                               inodes_avail = buff_statvfs.f_favail;
-                                                               inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
-                                                               inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
-
-                                                               st = rrdset_find_bytype("disk_inodes", disk);
-                                                               if(!st) {
-                                                                       st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
-                                                                       st->isdetail = 1;
-
-                                                                       rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                                                       rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
-                                                                       rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                                               }
-                                                               else rrdset_next_usec(st, dt);
-
-                                                               rrddim_set(st, "avail", inodes_avail);
-                                                               rrddim_set(st, "reserved_for_root", inodes_avail_root);
-                                                               rrddim_set(st, "used", inodes_used);
-                                                               rrdset_done(st);
+                                                       else rrdset_next_usec(st, dt);
+
+                                                       rrddim_set(st, "avail", space_avail);
+                                                       rrddim_set(st, "reserved_for_root", space_avail_root);
+                                                       rrddim_set(st, "used", space_used);
+                                                       rrdset_done(st);
+                                               }
+
+                                               // --------------------------------------------------------------------------
+
+                                               if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
+                                                       st = rrdset_find_bytype("disk_inodes", disk);
+                                                       if(!st) {
+                                                               st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
+                                                               st->isdetail = 1;
+
+                                                               rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                                                               rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+                                                               rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
                                                        }
+                                                       else rrdset_next_usec(st, dt);
+
+                                                       rrddim_set(st, "avail", inodes_avail);
+                                                       rrddim_set(st, "reserved_for_root", inodes_avail_root);
+                                                       rrddim_set(st, "used", inodes_used);
+                                                       rrdset_done(st);
                                                }
                                        }
                                }
                        }
                }
        }
+
        return 0;
 }
index 010b07dddc69a8a88253d6cc7bf16d28ca665332..bd22b8187fe05d335d3400a26386bd6c0c7cdbd8 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -63,31 +63,37 @@ char *url_encode(char *str) {
 /* Returns a url-decoded version of str */
 /* IMPORTANT: be sure to free() the returned string after use */
 char *url_decode(char *str) {
-       char *pstr = str,
-               *buf = malloc(strlen(str) + 1),
-               *pbuf = buf;
+       size_t size = strlen(str) + 1;
 
+       char *buf = malloc(size);
        if(!buf)
-               fatal("Cannot allocate memory.");
+               fatal("Cannot allocate %zu bytes of memory.", size);
+
+       return url_decode_r(buf, str, size);
+}
+
+char *url_decode_r(char *to, char *url, size_t size) {
+       char *s = url,           // source
+                *d = to,            // destination
+                *e = &to[size - 1]; // destination end
 
-       while (*pstr) {
-               if (*pstr == '%') {
-                       if (pstr[1] && pstr[2]) {
-                               *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
-                               pstr += 2;
+       while(*s && d < e) {
+               if(unlikely(*s == '%')) {
+                       if(likely(s[1] && s[2])) {
+                               *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
+                               s += 2;
                        }
                }
-               else if (*pstr == '+')
-                       *pbuf++ = ' ';
+               else if(unlikely(*s == '+'))
+                       *d++ = ' ';
 
                else
-                       *pbuf++ = *pstr;
+                       *d++ = *s;
 
-               pstr++;
+               s++;
        }
 
-       *pbuf = '\0';
+       *d = '\0';
 
-       return buf;
+       return to;
 }
-
index f79a20ea0c0f7973e4fe92a42522b008d7abe3e2..fa44d49a8e856d081f1907b85ae06dad45a37281 100644 (file)
--- a/src/url.h
+++ b/src/url.h
@@ -19,4 +19,6 @@ extern char *url_encode(char *str);
 /* IMPORTANT: be sure to free() the returned string after use */
 extern char *url_decode(char *str);
 
+extern char *url_decode_r(char *to, char *url, size_t size);
+
 #endif /* NETDATA_URL_H */
index 601dda083ae0172e4b65be9d0e9ecd3f19cc6264..9a784f41c31c4a0ef67e7998ea0f93fcc3e7e7b1 100644 (file)
@@ -146,6 +146,19 @@ void web_client_reset(struct web_client *w)
        struct timeval tv;
        gettimeofday(&tv, NULL);
 
+       debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
+
+       if(w->stats_received_bytes || w->stats_sent_bytes) {
+               global_statistics_lock();
+               global_statistics.web_requests++;
+               global_statistics.web_usec += usecdiff(&tv, &w->tv_in);
+               global_statistics.bytes_received += w->stats_received_bytes;
+               global_statistics.bytes_sent += w->stats_sent_bytes;
+               global_statistics_unlock();
+       }
+       w->stats_received_bytes = 0;
+       w->stats_sent_bytes = 0;
+
        long sent = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
 
 #ifdef NETDATA_WITH_ZLIB
@@ -166,8 +179,6 @@ void web_client_reset(struct web_client *w)
                        w->last_url
                );
 
-       debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
-
        if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
                debug(D_WEB_CLIENT, "%llu: Closing filecopy input file.", w->id);
                close(w->ifd);
@@ -181,12 +192,8 @@ void web_client_reset(struct web_client *w)
        w->origin[1] = '\0';
 
        w->mode = WEB_CLIENT_MODE_NORMAL;
-       w->enable_gzip = 0;
        w->keepalive = 0;
-       if(w->decoded_url) {
-               free(w->decoded_url);
-               w->decoded_url = NULL;
-       }
+       w->decoded_url[0] = '\0';
 
        buffer_reset(w->response.header_output);
        buffer_reset(w->response.header);
@@ -417,7 +424,7 @@ int mysendfile(struct web_client *w, char *filename)
 
 
 #ifdef NETDATA_WITH_ZLIB
-void web_client_enable_deflate(struct web_client *w) {
+void web_client_enable_deflate(struct web_client *w, int gzip) {
        if(w->response.zinitialized == 1) {
                error("%llu: Compression has already be initialized for this client.", w->id);
                return;
@@ -450,7 +457,7 @@ void web_client_enable_deflate(struct web_client *w) {
 //     }
 
        // Select GZIP compression: windowbits = 15 + 16 = 31
-       if(deflateInit2(&w->response.zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+       if(deflateInit2(&w->response.zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + ((gzip)?16:0), 8, Z_DEFAULT_STRATEGY) != Z_OK) {
                error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
                return;
        }
@@ -1221,8 +1228,13 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
        }
 #ifdef NETDATA_WITH_ZLIB
        else if(!strcasecmp(s, "Accept-Encoding")) {
-               if(web_enable_gzip && strcasestr(v, "gzip")) {
-                       w->enable_gzip = 1;
+               if(web_enable_gzip) {
+                       if(strcasestr(v, "gzip"))
+                               web_client_enable_deflate(w, 1);
+                       //
+                       // does not seem to work
+                       // else if(strcasestr(v, "deflate"))
+                       //      web_client_enable_deflate(w, 0);
                }
        }
 #endif /* NETDATA_WITH_ZLIB */
@@ -1235,7 +1247,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
 // http_request_validate()
 // returns:
 // = 0 : all good, process the request
-// > 0 : request is complete, but is not supported
+// > 0 : request is not supported
 // < 0 : request is incomplete - wait for more data
 
 static inline int http_request_validate(struct web_client *w) {
@@ -1257,7 +1269,7 @@ static inline int http_request_validate(struct web_client *w) {
 
        // find the SPACE + "HTTP/"
        while(*s) {
-               // find the space
+               // find the next space
                while (*s && *s != ' ') s++;
 
                // is it SPACE + "HTTP/" ?
@@ -1266,7 +1278,7 @@ static inline int http_request_validate(struct web_client *w) {
        }
 
        // incomplete requests
-       if(!*s) {
+       if(unlikely(!*s)) {
                w->wait_receive = 1;
                return -2;
        }
@@ -1274,32 +1286,37 @@ static inline int http_request_validate(struct web_client *w) {
        // we have the end of encoded_url - remember it
        char *ue = s;
 
+       // make sure we have complete request
+       // complete requests contain: \r\n\r\n
        while(*s) {
                // find a line feed
-               while (*s && *s != '\r') s++;
+               while(*s && *s++ != '\r');
 
                // did we reach the end?
                if(unlikely(!*s)) break;
 
                // is it \r\n ?
-               if (likely(s[1] == '\n')) {
+               if(likely(*s++ == '\n')) {
 
                        // is it again \r\n ? (header end)
-                       if(unlikely(s[2] == '\r' && s[3] == '\n')) {
+                       if(unlikely(*s == '\r' && s[1] == '\n')) {
                                // a valid complete HTTP request found
 
                                *ue = '\0';
-                               w->decoded_url = url_decode(encoded_url);
+                               url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
                                *ue = ' ';
+                               
+                               // copy the URL - we are going to overwrite parts of it
+                               // FIXME -- we should avoid it
+                               strncpyz(w->last_url, w->decoded_url, URL_MAX);
 
                                w->wait_receive = 0;
                                return 0;
                        }
 
                        // another header line
-                       s = http_header_parse(w, &s[2]);
+                       s = http_header_parse(w, s);
                }
-               else s++;
        }
 
        // incomplete request
@@ -1341,14 +1358,6 @@ void web_client_process(struct web_client *w) {
        else { // what_to_do == 0
                gettimeofday(&w->tv_in, NULL);
 
-               global_statistics_lock();
-               global_statistics.web_requests++;
-               global_statistics_unlock();
-
-               // copy the URL - we are going to overwrite parts of it
-               // FIXME -- we should avoid it
-               strncpyz(w->last_url, w->decoded_url, URL_MAX);
-
                if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
                        code = 200;
                        w->response.data->contenttype = CT_TEXT_PLAIN;
@@ -1356,11 +1365,6 @@ void web_client_process(struct web_client *w) {
                        buffer_strcat(w->response.data, "OK");
                }
                else {
-#ifdef NETDATA_WITH_ZLIB
-                       if(w->enable_gzip)
-                               web_client_enable_deflate(w);
-#endif
-
                        char *url = w->decoded_url;
                        char *tok = mystrsep(&url, "/?");
                        if(tok && *tok) {
@@ -1736,11 +1740,8 @@ void web_client_process(struct web_client *w) {
                                , w->id
                                , buffer_strlen(w->response.header_output)
                                , bytes);
-       else {
-               global_statistics_lock();
-               global_statistics.bytes_sent += bytes;
-               global_statistics_unlock();
-       }
+       else 
+               w->stats_sent_bytes += bytes;
 
        // enable TCP_NODELAY, to send all data immediately at the next send()
        flag = 1;
@@ -2107,10 +2108,8 @@ void *web_client_main(void *ptr)
                                errno = 0;
                                break;
                        }
-
-                       global_statistics_lock();
-                       global_statistics.bytes_sent += bytes;
-                       global_statistics_unlock();
+                       else
+                               w->stats_sent_bytes += bytes;
                }
 
                if(w->wait_receive && FD_ISSET(w->ifd, &ifds)) {
@@ -2120,6 +2119,8 @@ void *web_client_main(void *ptr)
                                errno = 0;
                                break;
                        }
+                       else
+                               w->stats_received_bytes += bytes;
 
                        if(w->mode == WEB_CLIENT_MODE_NORMAL) {
                                debug(D_WEB_CLIENT, "%llu: Attempting to process received data (%ld bytes).", w->id, bytes);
@@ -2127,9 +2128,6 @@ void *web_client_main(void *ptr)
                                web_client_process(w);
                        }
 
-                       global_statistics_lock();
-                       global_statistics.bytes_received += bytes;
-                       global_statistics_unlock();
                }
        }
 
index f663be4a1d28eec1279ae90cc8798bd642762782..da3707d20a3910c01c92e794b874fdc9144c19e8 100644 (file)
@@ -57,7 +57,8 @@ struct web_client {
        char client_ip[NI_MAXHOST+1];
        char client_port[NI_MAXSERV+1];
 
-       char last_url[URL_MAX+1];
+       char decoded_url[URL_MAX + 1];  // we decode the URL in this buffer
+       char last_url[URL_MAX+1];               // we keep a copy of the decoded URL here
 
        struct timeval tv_in, tv_ready;
 
@@ -68,7 +69,6 @@ struct web_client {
        int mode;
        int keepalive;
        int enable_gzip;
-       char *decoded_url;
 
        struct sockaddr_storage clientaddr;
 
@@ -83,6 +83,9 @@ struct web_client {
        int wait_receive;
        int wait_send;
 
+       unsigned long stats_received_bytes;
+       unsigned long stats_sent_bytes;
+
        struct web_client *prev;
        struct web_client *next;
 };