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