@cryptotaxi247 / netdata-1 / commits / e17976fb8

operational graphite backend

Costa Tsaousis (ktsaou) committed Nov 20, 2016 at 04:25 UTC e17976fb86af30fd250aa352b361073e1807bc81
1 file changed +140 -22
src/backends.c
+140 -22
@@ -154,32 +154,86 @@ static inline int connect_to_one(const char *definition, int default_port) {
154 return fd;
155 }
156
157 +static inline calculated_number backend_duration_average(RRDSET *st, RRDDIM *rd, time_t after, time_t before) {
158 + time_t first_t = rrdset_first_entry_t(st);
159 + time_t last_t = rrdset_last_entry_t(st);
160 +
161 + if(unlikely(before - after < st->update_every && after != after - after % st->update_every))
162 + // when st->update_every is bigger than the frequency we send data to backend
163 + // skip the iterations that are not aligned to the database
164 + return NAN;
165 +
166 + // align the time-frame
167 + // for 'after' also skip the first value by adding st->update_every
168 + after = after - after % st->update_every + st->update_every;
169 + before = before - before % st->update_every;
170 +
171 + if(unlikely(after < first_t))
172 + after = first_t;
173 +
174 + if(unlikely(after > before))
175 + // this can happen when the st->update_every > before - after
176 + before = after;
177 +
178 + if(unlikely(before > last_t))
179 + before = last_t;
180 +
181 + size_t counter = 0;
182 + calculated_number sum = 0;
183 +
184 + long start_at_slot = rrdset_time2slot(st, before),
185 + stop_at_slot = rrdset_time2slot(st, after),
186 + slot, stop_now = 0;
187 +
188 + for(slot = start_at_slot; !stop_now ; slot--) {
189 + if(unlikely(slot < 0)) slot = st->entries - 1;
190 + if(unlikely(slot == stop_at_slot)) stop_now = 1;
191 +
192 + storage_number n = rd->values[slot];
193 + if(unlikely(!does_storage_number_exist(n))) continue;
194 +
195 + calculated_number value = unpack_storage_number(n);
196 + sum += value;
197 + counter++;
198 + }
199 +
200 + if(!counter)
201 + return NAN;
202 +
203 + return sum / (calculated_number)counter;
204 +}
205 +
206 static inline void format_dimension_collected_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, RRDSET *st, RRDDIM *rd, time_t after, time_t before) {
207 + (void)before;
208 +
209 time_t last = rd->last_collected_time.tv_sec;
159 - if(likely(last >= after && last < before))
210 + if(likely(last > after))
211 buffer_sprintf(b, "%s.%s.%s.%s " COLLECTED_NUMBER_FORMAT " %u\n", prefix, host->hostname, st->id, rd->id, rd->last_collected_value, (uint32_t)last);
212 }
213
214 static inline void format_dimension_stored_graphite_plaintext(BUFFER *b, const char *prefix, RRDHOST *host, RRDSET *st, RRDDIM *rd, time_t after, time_t before) {
164 - time_t last = rd->last_collected_time.tv_sec;
165 - if(likely(last >= after && last < before))
166 - buffer_sprintf(b, "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n", prefix, host->hostname, st->id, rd->id, rd->last_stored_value, (uint32_t)last);
215 + calculated_number value = backend_duration_average(st, rd, after, before);
216 + if(!isnan(value))
217 + buffer_sprintf(b, "%s.%s.%s.%s " CALCULATED_NUMBER_FORMAT " %u\n", prefix, host->hostname, st->id, rd->id, value, (uint32_t)before);
218 }
219
220 static inline void format_dimension_collected_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, RRDSET *st, RRDDIM *rd, time_t after, time_t before) {
221 + (void)before;
222 +
223 time_t last = rd->last_collected_time.tv_sec;
171 - if(likely(last >= after && last < before))
224 + if(likely(last > after))
225 buffer_sprintf(b, "put %s.%s.%s %u " COLLECTED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t)last, rd->last_collected_value, host->hostname);
226 }
227
228 static inline void format_dimension_stored_opentsdb_telnet(BUFFER *b, const char *prefix, RRDHOST *host, RRDSET *st, RRDDIM *rd, time_t after, time_t before) {
176 - time_t last = rd->last_collected_time.tv_sec;
177 - if(likely(last >= after && last < before))
178 - buffer_sprintf(b, "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t)last, rd->last_stored_value, host->hostname);
229 + calculated_number value = backend_duration_average(st, rd, after, before);
230 + if(!isnan(value))
231 + buffer_sprintf(b, "put %s.%s.%s %u " CALCULATED_NUMBER_FORMAT " host=%s\n", prefix, st->id, rd->id, (uint32_t)before, value, host->hostname);
232 }
233
234 void *backends_main(void *ptr) {
235 (void)ptr;
236 +
237 BUFFER *b = buffer_create(1);
238 void (*formatter)(BUFFER *b, const char *prefix, RRDHOST *host, RRDSET *st, RRDDIM *rd, time_t after, time_t before);
239
@@ -192,12 +246,14 @@ void *backends_main(void *ptr) {
246 error("Cannot set pthread cancel state to ENABLE.");
247
248 int default_port = 0;
249 + int sock = -1;
250 int enabled = config_get_boolean("backends", "enable", 0);
251 const char *source = config_get("backends", "data source", "as stored");
252 const char *type = config_get("backends", "type", "graphite");
253 const char *destination = config_get("backends", "destination", "localhost");
254 const char *prefix = config_get("backends", "prefix", "netdata");
200 - int frequency = (int)config_get_number("backends", "update every", 10);
255 + int frequency = (int)config_get_number("backends", "update every", 30);
256 + int buffer_on_failures = (int)config_get_number("backends", "buffer on failures", 10);
257
258 if(!enabled)
259 goto cleanup;
@@ -221,23 +277,27 @@ void *backends_main(void *ptr) {
277 goto cleanup;
278 }
279
224 - time_t after, before = (time_t)(time_usec() / 10000000ULL);
280 + unsigned long long step_ut = frequency * 1000000ULL;
281 + unsigned long long random_ut = time_usec() % (step_ut / 2);
282 + time_t before = (time_t)((time_usec() - step_ut) / 10000000ULL);
283 + time_t after = before;
284 + int failures = 0;
285
226 - unsigned long long step = frequency * 1000000ULL;
286 for(;;) {
228 - unsigned long long now = time_usec();
229 - unsigned long long next = now - (now % step) + step + (step / 2);
287 + unsigned long long now_ut = time_usec();
288 + unsigned long long next_ut = now_ut - (now_ut % step_ut) + step_ut;
289 + before = (time_t)(next_ut / 1000000ULL);
290
231 - while(now < next) {
232 - sleep_usec(next - now);
233 - now = time_usec();
291 + // add a little delay (1/4 of the step) plus some randomness
292 + next_ut += (step_ut / 4) + random_ut;
293 +
294 + while(now_ut < next_ut) {
295 + sleep_usec(next_ut - now_ut);
296 + now_ut = time_usec();
297 }
298
236 - after = before;
237 - before = (time_t)(now / 10000000ULL);
299 RRDSET *st;
300 int pthreadoldcancelstate;
240 - buffer_flush(b);
301
302 if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &pthreadoldcancelstate) != 0))
303 error("Cannot set pthread cancel state to DISABLE.");
@@ -245,10 +305,11 @@ void *backends_main(void *ptr) {
305 rrdhost_rdlock(&localhost);
306 for(st = localhost.rrdset_root; st ;st = st->next) {
307 pthread_rwlock_rdlock(&st->rwlock);
308 +
309 RRDDIM *rd;
249 - for(rd = st->dimensions; rd ;rd = rd->next) {
310 + for(rd = st->dimensions; rd ;rd = rd->next)
311 formatter(b, prefix, &localhost, st, rd, after, before);
251 - }
312 +
313 pthread_rwlock_unlock(&st->rwlock);
314 }
315 rrdhost_unlock(&localhost);
@@ -258,10 +319,67 @@ void *backends_main(void *ptr) {
319
320 if(unlikely(netdata_exit)) break;
321
261 - break;
322 + //fprintf(stderr, "\nBACKEND BEGIN:\n%s\nBACKEND END\n", buffer_tostring(b));
323 + //fprintf(stderr, "after = %lu, before = %lu\n", after, before);
324 +
325 + if(unlikely(sock == -1)) {
326 + const char *s = destination;
327 + while(*s) {
328 + const char *e = s;
329 +
330 + // skip separators, moving both s(tart) and e(nd)
331 + while(isspace(*e) || *e == ',') s = ++e;
332 +
333 + // move e(nd) to the first separator
334 + while(*e && !isspace(*e) && *e != ',') e++;
335 +
336 + // is there anything?
337 + if(!*s || s == e) break;
338 +
339 + char buf[e - s + 1];
340 + strncpyz(buf, s, e - s);
341 + sock = connect_to_one(buf, default_port);
342 + if(sock != -1) break;
343 + s = e;
344 + }
345 + }
346 +
347 + if(unlikely(netdata_exit)) break;
348 +
349 + if(likely(sock != -1)) {
350 + size_t len = buffer_strlen(b);
351 + ssize_t written = write(sock, buffer_tostring(b), len);
352 + if(written != -1 && (size_t)written == len) {
353 + failures = 0;
354 + buffer_flush(b);
355 + }
356 + else {
357 + failures++;
358 + error("Failed to write data to database backend '%s'. Willing to write %zu bytes, wrote %zd bytes. Will re-connect.", destination, len, written);
359 + close(sock);
360 + sock = -1;
361 + }
362 +
363 + after = before;
364 + }
365 + else {
366 + failures++;
367 + error("Failed to update database backend '%s'", destination);
368 + }
369 +
370 + if(failures > buffer_on_failures) {
371 + error("Reached %d backend failures. Flushing buffers to protect this host - this results in data loss on back-end server '%s'", failures, destination);
372 + buffer_flush(b);
373 + failures = 0;
374 + }
375 +
376 + if(unlikely(netdata_exit)) break;
377 }
378
379 cleanup:
380 + if(sock != -1)
381 + close(sock);
382 +
383 info("BACKENDs thread exiting");
384
385 pthread_exit(NULL);