@cryptotaxi247 / netdata-1 / commits / 741f1ee1c

switched from mutexes to rwlocks - for normal update operations, now no thread locks

Costa Tsaousis (ktsaou) committed May 13, 2014 at 01:52 UTC 741f1ee1cb7e827f8ff32060055b661f8c29c37c
1 file changed +77 -71
netdata.c
+77 -71
@@ -532,7 +532,7 @@ int create_listen_socket(int port)
532 #define CONFIG_FILENAME "netdata.conf"
533 #define CONFIG_FILE_LINE_MAX 4096
534
535 -pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
535 +pthread_rwlock_t config_rwlock = PTHREAD_RWLOCK_INITIALIZER;
536
537 struct config_value {
538 char name[CONFIG_MAX_NAME + 1];
@@ -639,7 +639,7 @@ int load_config(char *filename, int overwrite_used)
639 int line = 0;
640 struct config *co = NULL;
641
642 - pthread_mutex_lock(&config_mutex);
642 + pthread_rwlock_wrlock(&config_rwlock);
643
644 char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
645
@@ -647,7 +647,7 @@ int load_config(char *filename, int overwrite_used)
647 FILE *fp = fopen(filename, "r");
648 if(!fp) {
649 error("Cannot open file '%s'", CONFIG_DIR "/" CONFIG_FILENAME);
650 - pthread_mutex_unlock(&config_mutex);
650 + pthread_rwlock_unlock(&config_rwlock);
651 return 0;
652 }
653
@@ -719,7 +719,7 @@ int load_config(char *filename, int overwrite_used)
719
720 fclose(fp);
721
722 - pthread_mutex_unlock(&config_mutex);
722 + pthread_rwlock_unlock(&config_rwlock);
723 return 1;
724 }
725
@@ -729,7 +729,7 @@ char *config_get(const char *section, const char *name, const char *default_valu
729
730 debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
731
732 - pthread_mutex_lock(&config_mutex);
732 + pthread_rwlock_rdlock(&config_rwlock);
733
734 struct config *co = config_find_section(section);
735 if(!co) co = config_create(section);
@@ -754,7 +754,7 @@ char *config_get(const char *section, const char *name, const char *default_valu
754 strncpy(cv->value, default_value, CONFIG_MAX_VALUE);
755 }
756
757 - pthread_mutex_unlock(&config_mutex);
757 + pthread_rwlock_unlock(&config_rwlock);
758 return(cv->value);
759 }
760
@@ -791,7 +791,7 @@ const char *config_set(const char *section, const char *name, const char *value)
791
792 debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
793
794 - pthread_mutex_lock(&config_mutex);
794 + pthread_rwlock_wrlock(&config_rwlock);
795
796 struct config *co = config_find_section(section);
797 if(!co) co = config_create(section);
@@ -810,7 +810,7 @@ const char *config_set(const char *section, const char *name, const char *value)
810 strncpy(cv->value, value, CONFIG_MAX_VALUE);
811 // termination is already there
812
813 - pthread_mutex_unlock(&config_mutex);
813 + pthread_rwlock_unlock(&config_rwlock);
814
815 return value;
816 }
@@ -988,8 +988,8 @@ typedef int32_t storage_number;
988 typedef uint32_t ustorage_number;
989 #define STORAGE_NUMBER_FORMAT "%d"
990
991 -#define RRD_STATS_MAGIC "NETDATA CACHE STATS FILE V001"
992 -#define RRD_DIMENSION_MAGIC "NETDATA CACHE DIMENSION FILE V002"
991 +#define RRD_STATS_MAGIC "NETDATA CACHE STATS FILE V005"
992 +#define RRD_DIMENSION_MAGIC "NETDATA CACHE DIMENSION FILE V005"
993
994 struct rrd_dimension {
995 char magic[sizeof(RRD_DIMENSION_MAGIC) + 1];// our magic
@@ -1037,7 +1037,7 @@ struct rrd_stats {
1037 char *title; // title shown to user
1038 char *units; // units of measurement
1039
1040 - pthread_mutex_t mutex;
1040 + pthread_rwlock_t rwlock;
1041 unsigned long counter; // the number of times we added values to this rrd
1042 unsigned long counter_since_reload; // the number of times we added values to this rrd
1043
@@ -1078,7 +1078,7 @@ struct rrd_stats {
1078 typedef struct rrd_stats RRD_STATS;
1079
1080 RRD_STATS *root = NULL;
1081 -pthread_mutex_t root_mutex = PTHREAD_MUTEX_INITIALIZER;
1081 +pthread_rwlock_t root_rwlock = PTHREAD_RWLOCK_INITIALIZER;
1082
1083 char *rrd_stats_strncpy_name(char *to, const char *from, int length)
1084 {
@@ -1234,13 +1234,13 @@ RRD_STATS *rrd_stats_create(const char *type, const char *id, const char *name,
1234 // initialize the next update
1235 if(!st->next_update.tv_sec) gettimeofday(&st->next_update, NULL);
1236
1237 - pthread_mutex_init(&st->mutex, NULL);
1238 - pthread_mutex_lock(&root_mutex);
1237 + pthread_rwlock_init(&st->rwlock, NULL);
1238 + pthread_rwlock_wrlock(&root_rwlock);
1239
1240 st->next = root;
1241 root = st;
1242
1243 - pthread_mutex_unlock(&root_mutex);
1243 + pthread_rwlock_unlock(&root_rwlock);
1244
1245 return(st);
1246 }
@@ -1367,18 +1367,17 @@ void rrd_stats_dimension_free(RRD_DIMENSION *rd)
1367
1368 void rrd_stats_free_all(void)
1369 {
1370 + pthread_rwlock_wrlock(&root_rwlock);
1371 RRD_STATS *st;
1371 - pthread_mutex_lock(&root_mutex);
1372 -
1372 for(st = root; st ;) {
1373 RRD_STATS *next = st->next;
1374
1376 - pthread_mutex_lock(&st->mutex);
1375 + pthread_rwlock_wrlock(&st->rwlock);
1376
1377 if(st->dimensions) rrd_stats_dimension_free(st->dimensions);
1378 st->dimensions = NULL;
1379
1381 - pthread_mutex_unlock(&st->mutex);
1380 + pthread_rwlock_unlock(&st->rwlock);
1381
1382 if(st->mapped) munmap(st, st->memsize);
1383 else free(st);
@@ -1386,24 +1385,21 @@ void rrd_stats_free_all(void)
1385 st = next;
1386 }
1387 root = NULL;
1389 -
1390 - pthread_mutex_unlock(&root_mutex);
1388 + pthread_rwlock_unlock(&root_rwlock);
1389 }
1390
1391 RRD_STATS *rrd_stats_find(const char *id)
1392 {
1393 unsigned long hash = simple_hash(id);
1394
1397 - pthread_mutex_lock(&root_mutex);
1398 -
1395 + pthread_rwlock_rdlock(&root_rwlock);
1396 RRD_STATS *st = root;
1400 -
1397 for ( ; st ; st = st->next )
1398 if(hash == st->hash)
1399 if(strcmp(st->id, id) == 0)
1400 break;
1401 + pthread_rwlock_unlock(&root_rwlock);
1402
1406 - pthread_mutex_unlock(&root_mutex);
1403 return(st);
1404 }
1405
@@ -1425,17 +1421,16 @@ RRD_STATS *rrd_stats_find_byname(const char *name)
1421 {
1422 char b[CONFIG_MAX_VALUE + 1];
1423
1428 - pthread_mutex_lock(&root_mutex);
1429 -
1424 rrd_stats_strncpy_name(b, name, CONFIG_MAX_VALUE);
1425 unsigned long hash = simple_hash(b);
1426
1427 + pthread_rwlock_rdlock(&root_rwlock);
1428 RRD_STATS *st = root;
1429 for ( ; st ; st = st->next ) {
1430 if(hash == st->hash_name && strcmp(st->name, b) == 0) break;
1431 }
1432 + pthread_rwlock_unlock(&root_rwlock);
1433
1438 - pthread_mutex_unlock(&root_mutex);
1434 return(st);
1435 }
1436
@@ -1487,8 +1482,8 @@ int rrd_stats_dimension_set(RRD_STATS *st, char *id, collected_number value)
1482
1483 void rrd_stats_next_usec(RRD_STATS *st, unsigned long long microseconds)
1484 {
1490 - // lock it to work with the dimensions
1491 - pthread_mutex_lock(&st->mutex);
1485 + // a read lock is OK here
1486 + pthread_rwlock_rdlock(&st->rwlock);
1487
1488 RRD_DIMENSION *rd;
1489 for( rd = st->dimensions; rd ; rd = rd->next ) {
@@ -1514,7 +1509,7 @@ void rrd_stats_next_usec(RRD_STATS *st, unsigned long long microseconds)
1509
1510 }
1511
1517 - pthread_mutex_unlock(&st->mutex);
1512 + pthread_rwlock_unlock(&st->rwlock);
1513
1514 return;
1515 }
@@ -1545,41 +1540,10 @@ void rrd_stats_next_plugins(RRD_STATS *st)
1540
1541 unsigned long long rrd_stats_done(RRD_STATS *st)
1542 {
1548 - pthread_mutex_lock(&st->mutex);
1549 -
1543 RRD_DIMENSION *rd, *last;
1544
1552 - // find if there are any obsolete dimensions (not updated recently)
1553 - for( rd = st->dimensions, last = NULL ; rd ; ) {
1554 - if((rd->last_updated.tv_sec + (10 * st->update_every)) < st->last_updated.tv_sec) { // remove it only it is not updated in 10 seconds
1555 - debug(D_RRD_STATS, "Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
1556 -
1557 - if(!last) {
1558 - st->dimensions = rd->next;
1559 - rd->next = NULL;
1560 - rrd_stats_dimension_free(rd);
1561 - rd = st->dimensions;
1562 - continue;
1563 - }
1564 - else {
1565 - last->next = rd->next;
1566 - rd->next = NULL;
1567 - rrd_stats_dimension_free(rd);
1568 - rd = last->next;
1569 - continue;
1570 - }
1571 - }
1572 -
1573 - last = rd;
1574 - rd = rd->next;
1575 - }
1576 -
1577 - if(!st->dimensions) {
1578 - st->enabled = 0;
1579 - pthread_mutex_unlock(&st->mutex);
1580 - // rrd_stats_free(st);
1581 - return(st->update_every * 1000000ULL);
1582 - }
1545 + // a read lock is OK here
1546 + pthread_rwlock_rdlock(&st->rwlock);
1547
1548 // calculate totals and count the dimensions
1549 st->absolute_total = 0;
@@ -1735,6 +1699,49 @@ unsigned long long rrd_stats_done(RRD_STATS *st)
1699 }
1700 // store the time difference to the last entry
1701 st->timediff[st->current_entry] = st->usec_since_last_update;
1702 +
1703 +
1704 + // ALL DONE ABOUT THE DATA UPDATE
1705 + // --------------------------------------------------------------------
1706 +
1707 +
1708 + // find if there are any obsolete dimensions (not updated recently)
1709 + for( rd = st->dimensions; rd ; rd = rd->next )
1710 + if((rd->last_updated.tv_sec + (10 * st->update_every)) < st->last_updated.tv_sec)
1711 + break;
1712 +
1713 + if(rd) {
1714 + // there is dimension to free
1715 + // upgrade our read lock to a write lock
1716 + pthread_rwlock_unlock(&st->rwlock);
1717 + pthread_rwlock_wrlock(&st->rwlock);
1718 +
1719 + for( rd = st->dimensions, last = NULL ; rd ; ) {
1720 + if((rd->last_updated.tv_sec + (10 * st->update_every)) < st->last_updated.tv_sec) { // remove it only it is not updated in 10 seconds
1721 + debug(D_RRD_STATS, "Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
1722 +
1723 + if(!last) {
1724 + st->dimensions = rd->next;
1725 + rd->next = NULL;
1726 + rrd_stats_dimension_free(rd);
1727 + rd = st->dimensions;
1728 + continue;
1729 + }
1730 + else {
1731 + last->next = rd->next;
1732 + rd->next = NULL;
1733 + rrd_stats_dimension_free(rd);
1734 + rd = last->next;
1735 + continue;
1736 + }
1737 + }
1738 +
1739 + last = rd;
1740 + rd = rd->next;
1741 + }
1742 +
1743 + if(!st->dimensions) st->enabled = 0;
1744 + }
1745 }
1746
1747 st->last_updated.tv_sec = st->next_update.tv_sec;
@@ -1742,8 +1749,7 @@ unsigned long long rrd_stats_done(RRD_STATS *st)
1749 st->counter++;
1750 st->counter_since_reload++;
1751
1745 - pthread_mutex_unlock(&st->mutex);
1746 -
1752 + pthread_rwlock_unlock(&st->rwlock);
1753 return(st->usec_since_last_update);
1754 }
1755
@@ -2041,7 +2047,7 @@ unsigned long rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer
2047 {
2048 web_buffer_increase(wb, 16384);
2049
2044 - pthread_mutex_lock(&st->mutex);
2050 + pthread_rwlock_rdlock(&st->rwlock);
2051
2052 web_buffer_printf(wb,
2053 "\t\t{\n"
@@ -2136,7 +2142,7 @@ unsigned long rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer
2142 , memory
2143 );
2144
2139 - pthread_mutex_unlock(&st->mutex);
2145 + pthread_rwlock_unlock(&st->rwlock);
2146 return memory;
2147 }
2148
@@ -2186,7 +2192,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
2192 unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int entries_to_show, int group, int group_method, time_t after, time_t before)
2193 {
2194 int c;
2189 - pthread_mutex_lock(&st->mutex);
2195 + pthread_rwlock_rdlock(&st->rwlock);
2196
2197
2198 // -------------------------------------------------------------------------
@@ -2232,7 +2238,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int
2238 RRD_DIMENSION *rd;
2239 for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
2240 if(!dimensions) {
2235 - pthread_mutex_unlock(&st->mutex);
2241 + pthread_rwlock_unlock(&st->rwlock);
2242 web_buffer_printf(wb, "No dimensions yet.");
2243 return 0;
2244 }
@@ -2432,7 +2438,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int
2438
2439 debug(D_RRD_STATS, "RRD_STATS_JSON: %s Generated %ld rows, total %ld bytes", st->name, printed, wb->bytes);
2440
2435 - pthread_mutex_unlock(&st->mutex);
2441 + pthread_rwlock_unlock(&st->rwlock);
2442 return last_timestamp;
2443 }
2444