@cryptotaxi247 / netdata-1 / commits / 6275b95ab

fixed memory leak

Costa Tsaousis (ktsaou) committed Apr 7, 2014 at 17:33 UTC 6275b95abaffd304ec75ff5d8e8480185e824d8c
1 file changed +114 -99
netdata.c
+114 -99
@@ -648,87 +648,6 @@ int rrd_stats_dimension_set(RRD_STATS *st, const char *id, void *data)
648 return 0;
649 }
650
651 -#define GROUP_AVERAGE 0
652 -#define GROUP_MAX 1
653 -
654 -size_t rrd_stats_one_json(RRD_STATS *st, char *options, char *buffer, size_t len)
655 -{
656 - size_t i = 0;
657 - if(i + 200 > len) return(0);
658 -
659 - i += sprintf(&buffer[i], "\t\t{\n");
660 - i += sprintf(&buffer[i], "\t\t\t\"id\" : \"%s\",\n", st->id);
661 - i += sprintf(&buffer[i], "\t\t\t\"name\" : \"%s\",\n", st->name);
662 - i += sprintf(&buffer[i], "\t\t\t\"type\" : \"%s\",\n", st->type);
663 - i += sprintf(&buffer[i], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
664 - i += sprintf(&buffer[i], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->id);
665 - i += sprintf(&buffer[i], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
666 - i += sprintf(&buffer[i], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
667 - i += sprintf(&buffer[i], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
668 - i += sprintf(&buffer[i], "\t\t\t\"hostname\" : \"%s\",\n", st->hostname);
669 - i += sprintf(&buffer[i], "\t\t\t\"vtitle\" : \"%s\",\n", st->vtitle);
670 - i += sprintf(&buffer[i], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
671 - i += sprintf(&buffer[i], "\t\t\t\"entries\" : %ld,\n", st->entries);
672 - i += sprintf(&buffer[i], "\t\t\t\"current\" : %ld,\n", st->current_entry);
673 - i += sprintf(&buffer[i], "\t\t\t\"update_every\" : %d,\n", update_every);
674 - i += sprintf(&buffer[i], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
675 - i += sprintf(&buffer[i], "\t\t\t\"last_updated_secs_ago\" : %lu\n", time(NULL) - st->last_updated);
676 - i += sprintf(&buffer[i], "\t\t}");
677 -
678 - return(i);
679 -}
680 -
681 -#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
682 -#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
683 -
684 -size_t rrd_stats_graph_json(RRD_STATS *st, char * options, char *buffer, size_t len)
685 -{
686 - size_t i = 0;
687 - i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
688 - i += rrd_stats_one_json(st, options, &buffer[i], len - i);
689 - i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
690 - return(i);
691 -}
692 -
693 -size_t rrd_stats_all_json(char *buffer, size_t len)
694 -{
695 - size_t i = 0, c;
696 - RRD_STATS *st;
697 -
698 - i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
699 -
700 - for(st = root, c = 0; st ; st = st->next, c++) {
701 - if(c) i += sprintf(&buffer[i], "%s", ",\n");
702 - i += rrd_stats_one_json(st, NULL, &buffer[i], len - i);
703 - }
704 -
705 - i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
706 - return(i);
707 -}
708 -
709 -long long rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
710 -{
711 - if(rd->bytes == sizeof(long long)) {
712 - long long *dimension = rd->values;
713 - return(dimension[position]);
714 - }
715 - else if(rd->bytes == sizeof(long)) {
716 - long *dimension = rd->values;
717 - return(dimension[position]);
718 - }
719 - else if(rd->bytes == sizeof(int)) {
720 - int *dimension = rd->values;
721 - return(dimension[position]);
722 - }
723 - else if(rd->bytes == sizeof(char)) {
724 - char *dimension = rd->values;
725 - return(dimension[position]);
726 - }
727 - else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
728 -
729 - return(0);
730 -}
731 -
651
652 // ----------------------------------------------------------------------------
653 // web buffer
@@ -783,7 +702,7 @@ void web_buffer_increase(struct web_buffer *b, size_t free_size_required)
702
703 debug(D_WEB_BUFFER, "Increasing data buffer from size %d to %d.", b->size, b->size + increase);
704
786 - b->buffer = realloc(b->buffer, b->size + free_size_required - left);
705 + b->buffer = realloc(b->buffer, b->size + increase);
706 if(!b->buffer) fatal("Failed to increase data buffer from size %d to %d.", b->size, b->size + increase);
707
708 b->size += increase;
@@ -796,6 +715,8 @@ struct web_client {
715 unsigned long long id;
716 char client_ip[101];
717
718 + struct timeval tv_in, tv_ready;
719 +
720 int mode;
721 int keepalive;
722
@@ -896,7 +817,86 @@ struct web_client *web_client_free(struct web_client *w)
817 return(n);
818 }
819
899 -size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
820 +#define GROUP_AVERAGE 0
821 +#define GROUP_MAX 1
822 +
823 +void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
824 +{
825 + web_buffer_increase(wb, 8192);
826 +
827 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t{\n");
828 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"id\" : \"%s\",\n", st->id);
829 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"name\" : \"%s\",\n", st->name);
830 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"type\" : \"%s\",\n", st->type);
831 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
832 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->id);
833 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
834 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
835 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
836 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"hostname\" : \"%s\",\n", st->hostname);
837 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"vtitle\" : \"%s\",\n", st->vtitle);
838 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
839 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"entries\" : %ld,\n", st->entries);
840 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"current\" : %ld,\n", st->current_entry);
841 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"update_every\" : %d,\n", update_every);
842 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
843 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated_secs_ago\" : %lu\n", time(NULL) - st->last_updated);
844 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t}");
845 +}
846 +
847 +#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
848 +#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
849 +
850 +void rrd_stats_graph_json(RRD_STATS *st, char *options, struct web_buffer *wb)
851 +{
852 + web_buffer_increase(wb, 4096);
853 +
854 + wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_HEADER);
855 + rrd_stats_one_json(st, options, wb);
856 + wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_FOOTER);
857 +}
858 +
859 +void rrd_stats_all_json(struct web_buffer *wb)
860 +{
861 + web_buffer_increase(wb, 4096);
862 +
863 + size_t c;
864 + RRD_STATS *st;
865 +
866 + wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_HEADER);
867 +
868 + for(st = root, c = 0; st ; st = st->next, c++) {
869 + if(c) wb->bytes += sprintf(&wb->buffer[wb->bytes], "%s", ",\n");
870 + rrd_stats_one_json(st, NULL, wb);
871 + }
872 +
873 + wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_FOOTER);
874 +}
875 +
876 +long long rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
877 +{
878 + if(rd->bytes == sizeof(long long)) {
879 + long long *dimension = rd->values;
880 + return(dimension[position]);
881 + }
882 + else if(rd->bytes == sizeof(long)) {
883 + long *dimension = rd->values;
884 + return(dimension[position]);
885 + }
886 + else if(rd->bytes == sizeof(int)) {
887 + int *dimension = rd->values;
888 + return(dimension[position]);
889 + }
890 + else if(rd->bytes == sizeof(char)) {
891 + char *dimension = rd->values;
892 + return(dimension[position]);
893 + }
894 + else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
895 +
896 + return(0);
897 +}
898 +
899 +void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
900 {
901 char *b = wb->buffer;
902
@@ -907,7 +907,6 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
907 if(group_count <= 0) group_count = 1;
908 if(group_count > st->entries / 20) group_count = st->entries / 20;
909
910 - size_t i = 0; // the bytes of JSON output we have generated so far
910 size_t printed = 0; // the lines of JSON data we have generated so far
911
912 size_t current_entry = st->current_entry;
@@ -932,7 +931,8 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
931
932 if(!dimensions) {
933 pthread_mutex_unlock(&st->mutex);
935 - return (wb->bytes = sprintf(b, "No dimensions yet."));
934 + wb->bytes = sprintf(b, "No dimensions yet.");
935 + return;
936 }
937
938 // temporary storage to keep track of group values and counts
@@ -941,14 +941,14 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
941 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
942 group_values[c] = group_counts[c] = 0;
943
944 - i += sprintf(&b[i], "{\n \"cols\":\n [\n");
945 - i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"}");
944 + wb->bytes += sprintf(&b[wb->bytes], "{\n \"cols\":\n [\n");
945 + wb->bytes += sprintf(&b[wb->bytes], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"}");
946
947 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
948 if(!rd->hidden)
949 - i += sprintf(&b[i], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
949 + wb->bytes += sprintf(&b[wb->bytes], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
950
951 - i += sprintf(&b[i], " ],\n \"rows\":\n [\n");
951 + wb->bytes += sprintf(&b[wb->bytes], " ],\n \"rows\":\n [\n");
952
953 // to allow grouping on the same values, we need a pad
954 pad = current_entry % group_count;
@@ -974,7 +974,7 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
974 if(!st->times[lt].tv_sec) continue;
975
976 // check if we may exceed the buffer provided
977 - web_buffer_increase(wb, 4096);
977 + web_buffer_increase(wb, 1024 + (50 * dimensions));
978
979 // prefer the most recent last entries
980 if(((count-pad) / group_count) > entries_to_show) continue;
@@ -995,7 +995,7 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
995 sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
996 // strftime(dtm, 200, "\"Date(%Y, %m, %d, %H, %M, %S)\"", tm); // datetime
997 // strftime(dtm, 200, "[%H, %M, %S, 0]", tm); // timeofday
998 - i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
998 + wb->bytes += sprintf(&b[wb->bytes], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
999
1000 printed++;
1001 }
@@ -1048,18 +1048,17 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
1048
1049 if(((count-pad) % group_count) == 0) {
1050 if(!rd->hidden)
1051 - i += sprintf(&b[i], ",{\"v\":%0.1Lf}", group_values[c]);
1052 - //i += sprintf(&b[i], ",{\"v\":%lld}", group_values[c]);
1051 + wb->bytes += sprintf(&b[wb->bytes], ",{\"v\":%0.1Lf}", group_values[c]);
1052 + //wb->bytes += sprintf(&b[wb->bytes], ",{\"v\":%lld}", group_values[c]);
1053
1054 group_values[c] = group_counts[c] = 0;
1055 }
1056 }
1057 }
1058 - if(printed) i += sprintf(&b[i], "]}");
1059 - i += sprintf(&b[i], "\n ]\n}\n");
1058 + if(printed) wb->bytes += sprintf(&b[wb->bytes], "]}");
1059 + wb->bytes += sprintf(&b[wb->bytes], "\n ]\n}\n");
1060
1061 pthread_mutex_unlock(&st->mutex);
1062 - return(wb->bytes = i);
1062 }
1063
1064 int mysendfile(struct web_client *w, char *filename)
@@ -1248,6 +1247,7 @@ void web_client_process(struct web_client *w)
1247
1248 // check if we have an empty line (end of HTTP header)
1249 if(strstr(w->data->buffer, "\r\n\r\n")) {
1250 + gettimeofday(&w->tv_in, NULL);
1251 debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
1252
1253 // check if the client requested keep-alive HTTP
@@ -1293,6 +1293,7 @@ void web_client_process(struct web_client *w)
1293 if(!st) {
1294 // we don't have it
1295 // try to send a file with that name
1296 + w->data->bytes = 0;
1297 code = mysendfile(w, tok);
1298 }
1299 else {
@@ -1330,7 +1331,8 @@ void web_client_process(struct web_client *w)
1331
1332 code = 200;
1333 w->data->contenttype = CT_APPLICATION_JSON;
1333 - w->data->bytes = rrd_stats_json(st, w->data, lines, group_count, group_method);
1334 + w->data->bytes = 0;
1335 + rrd_stats_json(st, w->data, lines, group_count, group_method);
1336 }
1337 }
1338 else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
@@ -1345,6 +1347,7 @@ void web_client_process(struct web_client *w)
1347 if(!st) {
1348 // we don't have it
1349 // try to send a file with that name
1350 + w->data->bytes = 0;
1351 code = mysendfile(w, tok);
1352 }
1353 else {
@@ -1352,7 +1355,8 @@ void web_client_process(struct web_client *w)
1355 syslog(LOG_NOTICE, "%llu: Sending '%s' graph to client %s.", w->id, st->name, w->client_ip);
1356 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1357 w->data->contenttype = CT_APPLICATION_JSON;
1355 - w->data->bytes = rrd_stats_graph_json(st, url, w->data->buffer, w->data->size);
1358 + w->data->bytes = 0;
1359 + rrd_stats_graph_json(st, url, w->data);
1360 }
1361 }
1362 else if(strcmp(tok, "mirror") == 0) {
@@ -1396,21 +1400,25 @@ void web_client_process(struct web_client *w)
1400 syslog(LOG_NOTICE, "%llu: Sending list with all graphs in JSON to client %s.", w->id, w->client_ip);
1401
1402 w->data->contenttype = CT_APPLICATION_JSON;
1399 - w->data->bytes = rrd_stats_all_json(w->data->buffer, w->data->size);
1403 + w->data->bytes = 0;
1404 + rrd_stats_all_json(w->data);
1405 }
1406 else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
1407 tok = mystrsep(&url, "/?&");
1408 if(tok && *tok) code = mysendfile(w, tok);
1409 else {
1410 code = 400;
1411 + w->data->bytes = 0;
1412 strcpy(w->data->buffer, "You have to give a filename to get.\r\n");
1413 w->data->bytes = strlen(w->data->buffer);
1414 }
1415 }
1416 else if(!tok[0]) {
1417 + w->data->bytes = 0;
1418 code = mysendfile(w, "index.html");
1419 }
1420 else {
1421 + w->data->bytes = 0;
1422 code = mysendfile(w, tok);
1423 }
1424 }
@@ -1418,6 +1426,7 @@ void web_client_process(struct web_client *w)
1426 if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
1427
1428 code = 500;
1429 + w->data->bytes = 0;
1430 strcpy(w->data->buffer, "I don't understand you...\r\n");
1431 w->data->bytes = strlen(w->data->buffer);
1432 }
@@ -1426,6 +1435,7 @@ void web_client_process(struct web_client *w)
1435 debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
1436
1437 code = 400;
1438 + w->data->bytes = 0;
1439 strcpy(w->data->buffer, "Received request is too big.\r\n");
1440 w->data->bytes = strlen(w->data->buffer);
1441 }
@@ -1435,6 +1445,11 @@ void web_client_process(struct web_client *w)
1445 return;
1446 }
1447
1448 + if(w->data->bytes > w->data->size) {
1449 + error("%llu: memory overflow encountered (size is %ld, written %ld).", w->data->size, w->data->bytes);
1450 + }
1451 +
1452 + gettimeofday(&w->tv_ready, NULL);
1453 w->data->date = time(NULL);
1454 w->data->sent = 0;
1455