@cryptotaxi247 / netdata-1 / commits / f40981dd1

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);