@cryptotaxi247 / netdata-1 / commits / 0146dd938

support range of data

Costa Tsaousis (ktsaou) committed Apr 21, 2014 at 23:06 UTC 0146dd93820f45e24b602a86eaf8db0cab56bbcb
1 file changed +67 -22
netdata.c
+67 -22
@@ -943,10 +943,29 @@ struct web_client *web_client_free(struct web_client *w)
943 #define GROUP_AVERAGE 0
944 #define GROUP_MAX 1
945
946 +// find the oldest entry in the data, skipping all empty slots
947 +size_t rrd_stats_first_entry(RRD_STATS *st)
948 +{
949 + size_t first_entry = st->current_entry + 1;
950 + if(first_entry >= st->entries) first_entry = 0;
951 +
952 + while(st->times[first_entry].tv_sec == 0 && first_entry != st->current_entry) {
953 + first_entry++;
954 + if(first_entry >= st->entries) first_entry = 0;
955 + }
956 +
957 + return first_entry;
958 +}
959 +
960 void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
961 {
962 web_buffer_increase(wb, 16384);
963
964 + pthread_mutex_lock(&st->mutex);
965 +
966 + size_t first_entry = rrd_stats_first_entry(st);
967 + time_t first_entry_t = st->times[first_entry].tv_sec;
968 +
969 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t{\n");
970 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"id\" : \"%s\",\n", st->id);
971 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"name\" : \"%s\",\n", st->name);
@@ -966,12 +985,16 @@ void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
985 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"units\" : \"%s\",\n", st->units);
986 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
987 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"entries\" : %ld,\n", st->entries);
969 - wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"current\" : %ld,\n", st->current_entry);
988 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry\" : %ld,\n", first_entry);
989 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry_t\" : %ld,\n", first_entry_t);
990 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry\" : %ld,\n", st->current_entry);
991 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_t\" : %lu,\n", st->last_updated);
992 + wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
993 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"update_every\" : %d,\n", update_every);
971 - wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
972 - wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
994 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"isdetail\" : %d\n", st->isdetail);
995 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t}");
996 +
997 + pthread_mutex_unlock(&st->mutex);
998 }
999
1000 #define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
@@ -1047,7 +1070,7 @@ long double rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
1070 return(0);
1071 }
1072
1050 -unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
1073 +unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method, time_t after, time_t before)
1074 {
1075 pthread_mutex_lock(&st->mutex);
1076
@@ -1070,14 +1093,12 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1093 // check the options
1094 if(entries_to_show <= 0) entries_to_show = 1;
1095 if(group_count <= 0) group_count = 1;
1073 - if(group_count > st->entries / 20) group_count = st->entries / 20;
1096 + // if(group_count > st->entries / 20) group_count = st->entries / 20;
1097
1098 size_t printed = 0; // the lines of JSON data we have generated so far
1099
1100 size_t current_entry = st->current_entry;
1101 size_t t, lt; // t = the current entry, lt = the lest entry of data
1079 - long count = st->entries; // count down of the entries examined so far
1080 - long pad = 0; // align the entries when grouping values together
1102
1103 RRD_DIMENSION *rd;
1104 size_t c = 0; // counter for dimension loops
@@ -1128,20 +1149,19 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1149
1150 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ],\n %srows%s:\n [\n", kq, kq);
1151
1131 - // to allow grouping on the same values, we need a pad
1132 - pad = current_entry % group_count;
1133 -
1152 // make sure current_entry is within limits
1153 if(current_entry < 0 || current_entry >= st->entries) current_entry = 0;
1154 + if(before == 0) before = st->times[current_entry].tv_sec;
1155
1137 - // find the old entry of the round-robin
1138 - t = current_entry + 1;
1139 - if(t >= st->entries) t = 0;
1156 + // find the oldest entry of the round-robin
1157 + t = rrd_stats_first_entry(st);
1158 lt = t;
1159 + size_t stop_entry = t;
1160
1142 - // find the current entry
1161 + // skip the oldest, to have incremental data
1162 t++;
1163 if(t >= st->entries) t = 0;
1164 + if(after == 0) after = st->times[t].tv_sec;
1165
1166 // the minimum line length we expect
1167 int line_size = 4096 + (dimensions * 200);
@@ -1154,23 +1174,30 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1174 int normal_annotation_len = snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1175 normal_annotation[200] = '\0';
1176
1177 + // count down of the entries examined so far
1178 + long count = ((before - after) / update_every) + 1;
1179 +
1180 + // to allow grouping on the same values, we need a pad
1181 + long pad = before % group_count;
1182 +
1183 + // debug(D_RRD_STATS, "after = %lu, before = %lu, diff = %lu, pad = %ld, count = %ld, entries_to_show = %lu, group_count = %lu, current_entry = %lu, t = %lu", after, before, before - after, pad, count, entries_to_show, group_count, current_entry, t);
1184 +
1185 // the loop in dimension data
1158 - count -= 2;
1186 int annotate_reset = 0;
1160 - for ( ; t != current_entry && count >= 0 ; lt = t++, count--) {
1187 + for ( ; t != stop_entry && count >= 0 ; lt = t++) {
1188 int print_this = 0;
1189
1190 if(t >= st->entries) t = 0;
1191
1165 - // if the last is empty, loop again
1166 - if(!st->times[lt].tv_sec) continue;
1192 + // make sure we return data in the proper time range
1193 + if(st->times[t].tv_sec < after || st->times[t].tv_sec > before) continue;
1194 + count--;
1195
1196 // check if we may exceed the buffer provided
1197 web_buffer_increase(wb, line_size);
1198
1199 // prefer the most recent last entries
1172 - if(((count-pad) / group_count) > entries_to_show) continue;
1173 -
1200 + if(((count-pad) / group_count) >= entries_to_show) continue;
1201
1202 // ok. we will use this entry!
1203 // find how much usec since the previous entry
@@ -1178,7 +1205,10 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1205 usec = usecdiff(&st->times[t], &st->times[lt]);
1206
1207 if(((count-pad) % group_count) == 0) {
1181 - if(printed >= entries_to_show) break;
1208 + if(printed >= entries_to_show) {
1209 + // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
1210 + break;
1211 + }
1212
1213 // generate the local date time
1214 struct tm *tm = localtime(&st->times[t].tv_sec);
@@ -1280,6 +1310,8 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1310 if(printed) wb->bytes += sprintf(&wb->buffer[wb->bytes], "]}");
1311 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ]\n}\n");
1312
1313 + // debug(D_RRD_STATS, "last_timestamp = %lu", last_timestamp);
1314 +
1315 pthread_mutex_unlock(&st->mutex);
1316 return last_timestamp;
1317 }
@@ -1508,6 +1540,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1540 // how many entries does the client want?
1541 size_t lines = save_history;
1542 size_t group_count = 1;
1543 + time_t after = 0, before = 0;
1544 int group_method = GROUP_AVERAGE;
1545
1546 if(url) {
@@ -1530,6 +1563,18 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1563 else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1564 else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1565 }
1566 + if(url) {
1567 + // parse after time
1568 + tok = mystrsep(&url, "/");
1569 + if(tok) after = strtoul(tok, NULL, 10);
1570 + if(after < 0) after = 0;
1571 + }
1572 + if(url) {
1573 + // parse before time
1574 + tok = mystrsep(&url, "/");
1575 + if(tok) before = strtoul(tok, NULL, 10);
1576 + if(before < 0) before = 0;
1577 + }
1578
1579 w->data->contenttype = CT_APPLICATION_JSON;
1580 w->data->bytes = 0;
@@ -1599,7 +1644,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1644 }
1645
1646 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group_count, %d group_method).", w->id, st->name, st->id, lines, group_count, group_method);
1602 - unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method);
1647 + unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method, after, before);
1648
1649 if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
1650 if(timestamp_in_data > last_timestamp_in_data)