added 'memory mode' config with 3 options: 'ram', 'map' and 'save'; ram will use just ram without any save-to-file capability; map will mmap() the files so that they updated continiously; save will save the files on exit; files generates with map and save are the same
Costa Tsaousis (ktsaou) committed
May 19, 2014 at 01:42 UTC
f40981dd19dc32d638f62b7f9ccde4843894b900
1 file changed
+119
-24
netdata.c
+119
-24
@@ -927,20 +927,63 @@ static void strreverse(char* begin, char* end)
927
// ----------------------------------------------------------------------------
928
// mmap() wrapper
929
930
-void *mymmap(const char *filename, unsigned long size)
930
+#define NETDATA_MEMORY_MODE_RAM_NAME "ram"
931
+#define NETDATA_MEMORY_MODE_MAP_NAME "map"
932
+#define NETDATA_MEMORY_MODE_SAVE_NAME "save"
933
+
934
+#define NETDATA_MEMORY_MODE_RAM 0
935
+#define NETDATA_MEMORY_MODE_MAP 1
936
+#define NETDATA_MEMORY_MODE_SAVE 2
937
+
938
+int memory_mode = NETDATA_MEMORY_MODE_SAVE;
939
+
940
+const char *memory_mode_name(int id)
941
{
932
- static int enabled = -1;
942
+ static const char *ram = NETDATA_MEMORY_MODE_RAM_NAME;
943
+ static const char *map = NETDATA_MEMORY_MODE_MAP_NAME;
944
+ static const char *save = NETDATA_MEMORY_MODE_SAVE_NAME;
945
+ const char *s = save;
946
+
947
+ switch(id) {
948
+ case NETDATA_MEMORY_MODE_RAM:
949
+ s = ram;
950
+ ;;
951
+
952
+ case NETDATA_MEMORY_MODE_MAP:
953
+ s = map;
954
+ ;;
955
934
- if(enabled == -1) {
935
- char *cache_dir = config_get("global", "cache data in directory", "cache");
936
- if(strcmp(cache_dir, "none") == 0) enabled = 0;
937
- else enabled = 1;
956
+ case NETDATA_MEMORY_MODE_SAVE:
957
+ default:
958
+ s = save;
959
+ ;;
960
}
939
- if(!enabled) return NULL;
961
941
- int fd;
962
+ return(s);
963
+}
964
+
965
+int memory_mode_id(const char *name)
966
+{
967
+ if(!strcmp(name, NETDATA_MEMORY_MODE_RAM_NAME))
968
+ return NETDATA_MEMORY_MODE_RAM;
969
+ else if(!strcmp(name, NETDATA_MEMORY_MODE_MAP_NAME))
970
+ return NETDATA_MEMORY_MODE_MAP;
971
+
972
+ return NETDATA_MEMORY_MODE_SAVE;
973
+}
974
+
975
+void *mymmap(const char *filename, unsigned long size)
976
+{
977
+ if(memory_mode == NETDATA_MEMORY_MODE_RAM) return NULL;
978
+
979
+ int fd, flags;
980
void *mem = NULL;
981
982
+ if(memory_mode == NETDATA_MEMORY_MODE_MAP)
983
+ flags = MAP_SHARED;
984
+ else
985
+ flags = MAP_PRIVATE;
986
+
987
errno = 0;
988
fd = open(filename, O_RDWR|O_CREAT|O_NOATIME, 0664);
989
if(fd != -1) {
@@ -950,7 +993,7 @@ void *mymmap(const char *filename, unsigned long size)
993
if(ftruncate(fd, size))
994
error("Cannot truncate file '%s' to size %ld. Will use the larger file.", filename, size);
995
953
- mem = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
996
+ mem = mmap(NULL, size, PROT_READ|PROT_WRITE, flags, fd, 0);
997
if(mem) {
998
if(madvise(mem, size, MADV_SEQUENTIAL|MADV_DONTFORK|MADV_WILLNEED) != 0)
999
error("Cannot advise the kernel about the memory usage of file '%s'.", filename);
@@ -967,6 +1010,35 @@ void *mymmap(const char *filename, unsigned long size)
1010
return mem;
1011
}
1012
1013
+int savememory(const char *filename, void *mem, unsigned long size)
1014
+{
1015
+ char tmpfilename[FILENAME_MAX + 1];
1016
+
1017
+ snprintf(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long)getpid());
1018
+
1019
+ int fd = open(tmpfilename, O_RDWR|O_CREAT|O_NOATIME, 0664);
1020
+ if(fd < 0) {
1021
+ error("Cannot create/open file '%s'.", filename);
1022
+ return -1;
1023
+ }
1024
+
1025
+ if(write(fd, mem, size) != (long)size) {
1026
+ error("Cannot write to file '%s' %ld bytes.", filename, (long)size);
1027
+ close(fd);
1028
+ return -1;
1029
+ }
1030
+
1031
+ close(fd);
1032
+
1033
+ int ret = 0;
1034
+ if(rename(tmpfilename, filename)) {
1035
+ error("Cannot rename '%s' to '%s'", tmpfilename, filename);
1036
+ ret = -1;
1037
+ }
1038
+
1039
+ return ret;
1040
+}
1041
+
1042
1043
// ----------------------------------------------------------------------------
1044
// RRD STATS
@@ -995,6 +1067,7 @@ struct rrd_dimension {
1067
char magic[sizeof(RRD_DIMENSION_MAGIC) + 1];// our magic
1068
char id[RRD_STATS_NAME_MAX + 1]; // the id of this dimension (for internal identification)
1069
char *name; // the name of this dimension (as presented to user)
1070
+ char cache_file[FILENAME_MAX+1];
1071
1072
unsigned long hash; // a simple hash on the id, to speed up searching
1073
// we first compare hashes, and only if the hashes are equal we do string comparisons
@@ -1031,6 +1104,7 @@ struct rrd_stats {
1104
char id[RRD_STATS_NAME_MAX + 1]; // id of the data set
1105
char *name; // name of the data set
1106
char *cache_dir; // the directory to store dimension maps
1107
+ char cache_file[FILENAME_MAX+1];
1108
1109
char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
1110
char *family; // the family of this data set (for grouping them together)
@@ -1106,21 +1180,17 @@ char *rrd_stats_cache_dir(const char *id)
1180
{
1181
char *ret = NULL;
1182
1109
- static int enabled = 1;
1183
static char *cache_dir = NULL;
1111
- if(!cache_dir) {
1112
- cache_dir = config_get("global", "cache data in directory", "cache");
1113
- if(strcmp(cache_dir, "none") == 0) enabled = 0;
1114
- }
1184
+ if(!cache_dir) cache_dir = config_get("global", "database directory", "cache");
1185
1186
char b[FILENAME_MAX + 1];
1187
char n[FILENAME_MAX + 1];
1188
rrd_stats_strncpy_name(b, id, FILENAME_MAX);
1189
1190
snprintf(n, FILENAME_MAX, "%s/%s", cache_dir, b);
1121
- ret = config_get(id, "cache_dir", n);
1191
+ ret = config_get(id, "database directory", n);
1192
1123
- if(enabled) {
1193
+ if(memory_mode == NETDATA_MEMORY_MODE_MAP || memory_mode == NETDATA_MEMORY_MODE_SAVE) {
1194
int r = mkdir(ret, 0775);
1195
if(r != 0 && errno != EEXIST)
1196
error("Cannot create directory '%s'", ret);
@@ -1188,7 +1258,7 @@ RRD_STATS *rrd_stats_create(const char *type, const char *id, const char *name,
1258
st->units = NULL;
1259
st->dimensions = NULL;
1260
st->next = NULL;
1191
- st->mapped = 1;
1261
+ st->mapped = memory_mode;
1262
}
1263
else {
1264
st = calloc(1, size);
@@ -1196,12 +1266,13 @@ RRD_STATS *rrd_stats_create(const char *type, const char *id, const char *name,
1266
fatal("Cannot allocate memory for RRD_STATS %s.%s", type, id);
1267
return NULL;
1268
}
1199
- st->mapped = 0;
1269
+ st->mapped = NETDATA_MEMORY_MODE_RAM;
1270
}
1271
st->memsize = size;
1272
st->entries = entries;
1273
st->update_every = update_every;
1274
1275
+ strcpy(st->cache_file, fullfilename);
1276
strcpy(st->magic, RRD_STATS_MAGIC);
1277
1278
strcpy(st->id, fullid);
@@ -1292,7 +1363,7 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char
1363
1364
if(rd) {
1365
// we have a file mapped for rd
1295
- rd->mapped = 1;
1366
+ rd->mapped = memory_mode;
1367
rd->hidden = 0;
1368
rd->next = NULL;
1369
rd->name = NULL;
@@ -1306,11 +1377,12 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char
1377
return NULL;
1378
}
1379
1309
- rd->mapped = 0;
1380
+ rd->mapped = NETDATA_MEMORY_MODE_RAM;
1381
}
1382
rd->memsize = size;
1383
1384
strcpy(rd->magic, RRD_DIMENSION_MAGIC);
1385
+ strcpy(rd->cache_file, fullfilename);
1386
strncpy(rd->id, id, RRD_STATS_NAME_MAX);
1387
rd->hash = simple_hash(rd->id);
1388
@@ -1352,7 +1424,14 @@ void rrd_stats_dimension_free(RRD_DIMENSION *rd)
1424
{
1425
if(rd->next) rrd_stats_dimension_free(rd->next);
1426
// free(rd->annotations);
1355
- if(rd->mapped) {
1427
+ if(rd->mapped == NETDATA_MEMORY_MODE_SAVE) {
1428
+ debug(D_RRD_STATS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_file);
1429
+ savememory(rd->cache_file, rd, rd->memsize);
1430
+
1431
+ debug(D_RRD_STATS, "Unmapping dimension '%s'.", rd->name);
1432
+ munmap(rd, rd->memsize);
1433
+ }
1434
+ else if(rd->mapped == NETDATA_MEMORY_MODE_MAP) {
1435
debug(D_RRD_STATS, "Unmapping dimension '%s'.", rd->name);
1436
munmap(rd, rd->memsize);
1437
}
@@ -1374,10 +1453,22 @@ void rrd_stats_free_all(void)
1453
if(st->dimensions) rrd_stats_dimension_free(st->dimensions);
1454
st->dimensions = NULL;
1455
1377
- pthread_rwlock_unlock(&st->rwlock);
1456
+ // we leave it locked, or other threads may crash...
1457
+ // pthread_rwlock_unlock(&st->rwlock);
1458
1379
- if(st->mapped) munmap(st, st->memsize);
1380
- else free(st);
1459
+ if(st->mapped == NETDATA_MEMORY_MODE_SAVE) {
1460
+ debug(D_RRD_STATS, "Saving stats '%s' to '%s'.", st->name, st->cache_file);
1461
+ savememory(st->cache_file, st, st->memsize);
1462
+
1463
+ debug(D_RRD_STATS, "Unmapping stats '%s'.", st->name);
1464
+ munmap(st, st->memsize);
1465
+ }
1466
+ else if(st->mapped == NETDATA_MEMORY_MODE_MAP) {
1467
+ debug(D_RRD_STATS, "Unmapping stats '%s'.", st->name);
1468
+ munmap(st, st->memsize);
1469
+ }
1470
+ else
1471
+ free(st);
1472
1473
st = next;
1474
}
@@ -6968,6 +7059,10 @@ int main(int argc, char **argv)
7059
7060
// --------------------------------------------------------------------
7061
7062
+ memory_mode = memory_mode_id(config_get("global", "memory mode", memory_mode_name(memory_mode)));
7063
+
7064
+ // --------------------------------------------------------------------
7065
+
7066
if(gethostname(buffer, HOSTNAME_MAX) == -1)
7067
error("WARNING: Cannot get machine hostname.");
7068
hostname = config_get("global", "hostname", buffer);