master
c 534 lines 18.3 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "rrdcontext-internal.h"
4
5 // ----------------------------------------------------------------------------
6 // helper one-liners for RRDINSTANCE
7
8 bool rrdinstance_acquired_id_and_name_are_same(RRDINSTANCE_ACQUIRED *ria) {
9 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
10 return ri->id == ri->name;
11 }
12
13 inline const char *rrdinstance_acquired_id(RRDINSTANCE_ACQUIRED *ria) {
14 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
15 return string2str(ri->id);
16 }
17
18 inline const char *rrdinstance_acquired_name(RRDINSTANCE_ACQUIRED *ria) {
19 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
20 return string2str(ri->name);
21 }
22
23 inline bool rrdinstance_acquired_has_name(RRDINSTANCE_ACQUIRED *ria) {
24 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
25 return (ri->name && ri->name != ri->id);
26 }
27
28 inline const char *rrdinstance_acquired_units(RRDINSTANCE_ACQUIRED *ria) {
29 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
30 return string2str(ri->units);
31 }
32
33 inline STRING *rrdinstance_acquired_units_dup(RRDINSTANCE_ACQUIRED *ria) {
34 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
35 return string_dup(ri->units);
36 }
37
38 inline RRDLABELS *rrdinstance_labels(RRDINSTANCE *ri) {
39 if(ri->rrdset)
40 return ri->rrdset->rrdlabels;
41
42 if (rrd_flag_check_all(ri, RRD_FLAG_OWN_LABELS | RRD_FLAG_DEMAND_LABELS)) {
43 rrd_flag_clear(ri, RRD_FLAG_DEMAND_LABELS);
44 load_instance_labels_on_demand(uuidmap_uuid_ptr(ri->uuid), ri);
45 rrdinstance_trigger_updates(ri, __FUNCTION__ );
46 }
47
48 return ri->rrdlabels;
49 }
50
51 inline RRDLABELS *rrdinstance_acquired_labels(RRDINSTANCE_ACQUIRED *ria) {
52 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
53 return rrdinstance_labels(ri);
54 }
55
56 inline DICTIONARY *rrdinstance_acquired_functions(RRDINSTANCE_ACQUIRED *ria) {
57 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
58 if(!ri->rrdset) return NULL;
59 return ri->rrdset->functions_view;
60 }
61
62 inline RRDHOST *rrdinstance_acquired_rrdhost(RRDINSTANCE_ACQUIRED *ria) {
63 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
64 return ri->rc->rrdhost;
65 }
66
67 inline bool rrdinstance_acquired_belongs_to_context(RRDINSTANCE_ACQUIRED *ria, RRDCONTEXT_ACQUIRED *rca) {
68 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
69 RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
70 return ri->rc == rc;
71 }
72
73 inline time_t rrdinstance_acquired_update_every(RRDINSTANCE_ACQUIRED *ria) {
74 RRDINSTANCE *ri = rrdinstance_acquired_value(ria);
75 return ri->update_every_s;
76 }
77
78 // ----------------------------------------------------------------------------
79 // RRDINSTANCE
80
81 static void rrdinstance_free(RRDINSTANCE *ri) {
82
83 if(rrd_flag_check(ri, RRD_FLAG_OWN_LABELS))
84 rrdlabels_destroy(ri->rrdlabels);
85
86 rrdmetrics_destroy_from_rrdinstance(ri);
87 string_freez(ri->id);
88 string_freez(ri->name);
89 string_freez(ri->title);
90 string_freez(ri->units);
91 string_freez(ri->family);
92 uuidmap_free(ri->uuid);
93
94 ri->id = NULL;
95 ri->name = NULL;
96 ri->title = NULL;
97 ri->units = NULL;
98 ri->family = NULL;
99 ri->uuid = 0;
100
101 ri->rc = NULL;
102 ri->rrdlabels = NULL;
103 ri->rrdmetrics = NULL;
104 ri->rrdset = NULL;
105 }
106
107 static void rrdinstance_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdcontext) {
108 RRDINSTANCE *ri = value;
109
110 // link it to its parent
111 ri->rc = rrdcontext;
112
113 ri->flags = ri->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS; // no need for atomics
114
115 if(!ri->name)
116 ri->name = string_dup(ri->id);
117
118 ri->rrdlabels = rrdlabels_create();
119
120 if(ri->rrdset)
121 ri->flags &= ~(RRD_FLAG_OWN_LABELS| RRD_FLAG_DEMAND_LABELS); // no need of atomics at the constructor
122 else
123 ri->flags |= (RRD_FLAG_OWN_LABELS | RRD_FLAG_DEMAND_LABELS); // no need of atomics at the constructor
124
125 if(ri->rrdset) {
126 if(unlikely(rrdset_flag_check(ri->rrdset, RRDSET_FLAG_HIDDEN)))
127 ri->flags |= RRD_FLAG_HIDDEN; // no need of atomics at the constructor
128 else
129 ri->flags &= ~RRD_FLAG_HIDDEN; // no need of atomics at the constructor
130 }
131
132 rrdmetrics_create_in_rrdinstance(ri);
133
134 // update the count of instances
135 __atomic_add_fetch(&ri->rc->rrdhost->rrdctx.instances_count, 1, __ATOMIC_RELAXED);
136
137 // signal the react callback to do the job
138 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
139 }
140
141 static void rrdinstance_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdcontext __maybe_unused) {
142 RRDINSTANCE *ri = (RRDINSTANCE *)value;
143
144 internal_error(ri->rrdset, "RRDINSTANCE: '%s' is freed but there is a RRDSET linked to it.", string2str(ri->id));
145
146 // update the count of instances
147 __atomic_sub_fetch(&ri->rc->rrdhost->rrdctx.instances_count, 1, __ATOMIC_RELAXED);
148
149 rrdinstance_free(ri);
150 }
151
152 static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *rrdcontext __maybe_unused) {
153 RRDINSTANCE *ri = (RRDINSTANCE *)old_value;
154 RRDINSTANCE *ri_new = (RRDINSTANCE *)new_value;
155
156 internal_error(ri->id != ri_new->id,
157 "RRDINSTANCE: '%s' cannot change id to '%s'",
158 string2str(ri->id), string2str(ri_new->id));
159
160 if(ri->uuid != ri_new->uuid) {
161 #ifdef NETDATA_INTERNAL_CHECKS
162 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
163 uuid_unparse(*uuidmap_uuid_ptr(ri->uuid), uuid1);
164 uuid_unparse(*uuidmap_uuid_ptr(ri_new->uuid), uuid2);
165 internal_error(true, "RRDINSTANCE: '%s' of host '%s' changed UUID from '%s' to '%s'",
166 string2str(ri->id), rrdhost_hostname(ri->rc->rrdhost), uuid1, uuid2);
167 #endif
168
169 SWAP(ri->uuid, ri_new->uuid);
170 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
171 }
172
173 if(ri->name != ri_new->name) {
174 SWAP(ri->name, ri_new->name);
175 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
176 }
177
178 if(ri->title != ri_new->title) {
179 SWAP(ri->title, ri_new->title);
180 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
181 }
182
183 if(ri->units != ri_new->units) {
184 SWAP(ri->units, ri_new->units);
185 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
186 }
187
188 if(ri->family != ri_new->family) {
189 SWAP(ri->family, ri_new->family);
190 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
191 }
192
193 if(ri->chart_type != ri_new->chart_type) {
194 ri->chart_type = ri_new->chart_type;
195 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
196 }
197
198 if(ri->priority != ri_new->priority) {
199 ri->priority = ri_new->priority;
200 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
201 }
202
203 if(ri->update_every_s != ri_new->update_every_s) {
204 ri->update_every_s = ri_new->update_every_s;
205 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
206 }
207
208 if(ri_new->rrdset && ri->rrdset != ri_new->rrdset) {
209 ri->rrdset = ri_new->rrdset;
210 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_LINKING);
211 }
212
213 if(ri->rrdset) {
214 // our labels are not needed any more
215 rrdlabels_flush(ri->rrdlabels);
216
217 if(unlikely(rrdset_flag_check(ri->rrdset, RRDSET_FLAG_HIDDEN)))
218 rrd_flag_set(ri, RRD_FLAG_HIDDEN);
219 else
220 rrd_flag_clear(ri, RRD_FLAG_HIDDEN);
221 }
222
223 rrd_flag_set(ri, ri_new->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS); // no need for atomics on ri_new
224
225 if(rrd_flag_is_collected(ri) && rrd_flag_is_archived(ri))
226 rrdinstance_set_collected(ri);
227
228 if(rrd_flag_is_updated(ri))
229 rrd_flag_set(ri, RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT);
230
231 // free the new one
232 rrdinstance_free(ri_new);
233
234 // the react callback will continue from here
235 return rrd_flag_is_updated(ri);
236 }
237
238 static void rrdinstance_react_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdcontext __maybe_unused) {
239 RRDINSTANCE *ri = value;
240
241 rrdinstance_trigger_updates(ri, __FUNCTION__ );
242 }
243
244 void rrdinstances_create_in_rrdcontext(RRDCONTEXT *rc) {
245 if(unlikely(!rc || rc->rrdinstances)) return;
246
247 rc->rrdinstances = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
248 &dictionary_stats_category_rrdcontext, sizeof(RRDINSTANCE));
249
250 dictionary_register_insert_callback(rc->rrdinstances, rrdinstance_insert_callback, rc);
251 dictionary_register_delete_callback(rc->rrdinstances, rrdinstance_delete_callback, rc);
252 dictionary_register_conflict_callback(rc->rrdinstances, rrdinstance_conflict_callback, rc);
253 dictionary_register_react_callback(rc->rrdinstances, rrdinstance_react_callback, rc);
254 }
255
256 void rrdinstances_destroy_from_rrdcontext(RRDCONTEXT *rc) {
257 if(unlikely(!rc || !rc->rrdinstances)) return;
258
259 dictionary_destroy(rc->rrdinstances);
260 rc->rrdinstances = NULL;
261 }
262
263 void rrdinstance_trigger_updates(RRDINSTANCE *ri, const char *function) {
264 RRDSET *st = ri->rrdset;
265
266 if(likely(st)) {
267 if(unlikely((unsigned int) st->priority != ri->priority)) {
268 ri->priority = st->priority;
269 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
270 }
271 if(unlikely(st->update_every != ri->update_every_s)) {
272 ri->update_every_s = st->update_every;
273 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
274 }
275 }
276 else if(unlikely(rrd_flag_is_collected(ri))) {
277 // there is no rrdset, but we have it as collected!
278
279 rrdinstance_set_archived(ri);
280 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_LINKING);
281 }
282
283 if(rrd_flag_is_updated(ri) || !rrd_flag_check(ri, RRD_FLAG_LIVE_RETENTION)) {
284 rrd_flag_set_updated(ri->rc, RRD_FLAG_UPDATE_REASON_TRIGGERED);
285 rrdcontext_queue_for_post_processing(ri->rc, function, ri->flags);
286 }
287 }
288
289 // ----------------------------------------------------------------------------
290 // RRDINSTANCE HOOKS ON RRDSET
291
292 inline void rrdinstance_from_rrdset(RRDSET *st) {
293 RRDCONTEXT trc = {
294 .id = string_dup(st->context),
295 .title = string_dup(st->title),
296 .units = string_dup(st->units),
297 .family = string_dup(st->family),
298 .priority = st->priority,
299 .chart_type = st->chart_type,
300 .flags = RRD_FLAG_NONE, // no need for atomics
301 .rrdhost = st->rrdhost,
302 };
303
304 RRDCONTEXT_ACQUIRED *rca = (RRDCONTEXT_ACQUIRED *)dictionary_set_and_acquire_item(st->rrdhost->rrdctx.contexts, string2str(trc.id), &trc, sizeof(trc));
305 RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
306
307 RRDINSTANCE tri = {
308 .uuid = uuidmap_create(st->chart_uuid),
309 .id = string_dup(st->id),
310 .name = string_dup(st->name),
311 .units = string_dup(st->units),
312 .family = string_dup(st->family),
313 .title = string_dup(st->title),
314 .chart_type = st->chart_type,
315 .priority = st->priority,
316 .update_every_s = st->update_every,
317 .flags = RRD_FLAG_NONE, // no need for atomics
318 .rrdset = st,
319 };
320
321 RRDINSTANCE_ACQUIRED *ria = (RRDINSTANCE_ACQUIRED *)dictionary_set_and_acquire_item(rc->rrdinstances, string2str(tri.id), &tri, sizeof(tri));
322
323 RRDCONTEXT_ACQUIRED *rca_old = st->rrdcontexts.rrdcontext;
324 RRDINSTANCE_ACQUIRED *ria_old = st->rrdcontexts.rrdinstance;
325
326 st->rrdcontexts.rrdcontext = rca;
327 st->rrdcontexts.rrdinstance = ria;
328
329 if(rca == rca_old) {
330 rrdcontext_release(rca_old);
331 rca_old = NULL;
332 }
333
334 if(ria == ria_old) {
335 rrdinstance_release(ria_old);
336 ria_old = NULL;
337 }
338
339 if(rca_old && ria_old) {
340 // Oops! The chart changed context!
341
342 // RRDCONTEXT *rc_old = rrdcontext_acquired_value(rca_old);
343 RRDINSTANCE *ri_old = rrdinstance_acquired_value(ria_old);
344
345 // migrate all dimensions to the new metrics
346 RRDDIM *rd;
347 rrddim_foreach_read(rd, st) {
348 if (!rd->rrdcontexts.rrdmetric) continue;
349
350 RRDMETRIC *rm_old = rrdmetric_acquired_value(rd->rrdcontexts.rrdmetric);
351 rrdmetric_set_deleted_overwrite(rm_old, RRD_FLAG_UPDATED|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
352 rrdmetric_rrddim_atomic_store(rm_old, NULL);
353 rm_old->first_time_s = 0;
354 rm_old->last_time_s = 0;
355
356 rrdmetric_release(rd->rrdcontexts.rrdmetric);
357 rd->rrdcontexts.rrdmetric = NULL;
358
359 rrdmetric_from_rrddim(rd);
360 }
361 rrddim_foreach_done(rd);
362
363 // mark the old instance, ready to be deleted
364 if(!rrd_flag_check(ri_old, RRD_FLAG_OWN_LABELS))
365 ri_old->rrdlabels = rrdlabels_create();
366
367 rrdinstance_set_deleted_overwrite(ri_old, RRD_FLAG_UPDATED|RRD_FLAG_OWN_LABELS|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
368 ri_old->rrdset = NULL;
369 ri_old->first_time_s = 0;
370 ri_old->last_time_s = 0;
371
372 rrdinstance_trigger_updates(ri_old, __FUNCTION__ );
373 rrdinstance_release(ria_old);
374
375 /*
376 // trigger updates on the old context
377 if(!dictionary_entries(rc_old->rrdinstances) && !dictionary_stats_referenced_items(rc_old->rrdinstances)) {
378 rrdcontext_lock(rc_old);
379 rc_old->flags = ((rc_old->flags & RRD_FLAG_QUEUED)?RRD_FLAG_QUEUED:RRD_FLAG_NONE)|RRD_FLAG_DELETED|RRD_FLAG_UPDATED|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION;
380 rc_old->first_time_s = 0;
381 rc_old->last_time_s = 0;
382 rrdcontext_unlock(rc_old);
383 rrdcontext_trigger_updates(rc_old, __FUNCTION__ );
384 }
385 else
386 rrdcontext_trigger_updates(rc_old, __FUNCTION__ );
387 */
388
389 rrdcontext_release(rca_old);
390 rca_old = NULL;
391 ria_old = NULL;
392 }
393
394 if(rca_old || ria_old)
395 fatal("RRDCONTEXT: cannot switch rrdcontext without switching rrdinstance too");
396 }
397
398 #define rrdset_get_rrdinstance(st) rrdset_get_rrdinstance_with_trace(st, __FUNCTION__)
399 static inline RRDINSTANCE *rrdset_get_rrdinstance_with_trace(RRDSET *st, const char *function) {
400 if(unlikely(!st->rrdcontexts.rrdinstance)) {
401 netdata_log_error("RRDINSTANCE: RRDSET '%s' is not linked to an RRDINSTANCE at %s()", rrdset_id(st), function);
402 return NULL;
403 }
404
405 RRDINSTANCE *ri = rrdinstance_acquired_value(st->rrdcontexts.rrdinstance);
406 if(unlikely(!ri)) {
407 netdata_log_error("RRDINSTANCE: RRDSET '%s' lost its link to an RRDINSTANCE at %s()", rrdset_id(st), function);
408 return NULL;
409 }
410
411 if(unlikely(ri->rrdset != st))
412 fatal("RRDINSTANCE: '%s' is not linked to RRDSET '%s' at %s()", string2str(ri->id), rrdset_id(st), function);
413
414 return ri;
415 }
416
417 ALWAYS_INLINE void rrdinstance_rrdset_not_collected(RRDSET *st) {
418 st->rrdcontexts.collected = false;
419
420 RRDDIM *rd;
421 rrddim_foreach_read(rd, st) {
422 rrdmetric_not_collected_rrddim(rd);
423 }
424 rrddim_foreach_done(rd);
425 }
426
427 inline void rrdinstance_rrdset_is_freed(RRDSET *st) {
428 rrdinstance_rrdset_not_collected(st);
429
430 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
431 if(unlikely(!ri)) return;
432
433 rrdinstance_set_archived(ri);
434
435 SWAP(ri->rrdlabels, st->rrdlabels);
436 rrd_flag_set(ri, RRD_FLAG_OWN_LABELS);
437
438 ri->rrdset = NULL;
439
440 rrdinstance_trigger_updates(ri, __FUNCTION__ );
441
442 rrdinstance_release(st->rrdcontexts.rrdinstance);
443 st->rrdcontexts.rrdinstance = NULL;
444
445 rrdcontext_release(st->rrdcontexts.rrdcontext);
446 st->rrdcontexts.rrdcontext = NULL;
447 }
448
449 ALWAYS_INLINE void rrdinstance_rrdset_has_updated_retention(RRDSET *st) {
450 // rrdinstance_rrdset_not_collected(st);
451
452 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
453 if(unlikely(!ri)) return;
454
455 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_UPDATE_RETENTION);
456 rrdinstance_trigger_updates(ri, __FUNCTION__ );
457 }
458
459 inline void rrdinstance_updated_rrdset_name(RRDSET *st) {
460 rrdinstance_rrdset_not_collected(st);
461
462 // the chart may not be initialized when this is called
463 if(unlikely(!st->rrdcontexts.rrdinstance)) return;
464
465 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
466 if(unlikely(!ri)) return;
467
468 if(st->name != ri->name) {
469 STRING *old = ri->name;
470 ri->name = string_dup(st->name);
471 string_freez(old);
472
473 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
474 rrdinstance_trigger_updates(ri, __FUNCTION__ );
475 }
476 }
477
478 inline void rrdinstance_updated_rrdset_flags_no_action(RRDINSTANCE *ri, RRDSET *st) {
479 if(unlikely(ri->rrdset != st))
480 fatal("RRDCONTEXT: instance '%s' is not linked to chart '%s' on host '%s'",
481 string2str(ri->id), rrdset_id(st), rrdhost_hostname(st->rrdhost));
482
483 bool st_is_hidden = rrdset_flag_check(st, RRDSET_FLAG_HIDDEN);
484 bool ri_is_hidden = rrd_flag_check(ri, RRD_FLAG_HIDDEN);
485
486 if(unlikely(st_is_hidden != ri_is_hidden)) {
487 if (unlikely(st_is_hidden && !ri_is_hidden))
488 rrd_flag_set_updated(ri, RRD_FLAG_HIDDEN | RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
489
490 else if (unlikely(!st_is_hidden && ri_is_hidden)) {
491 rrd_flag_clear(ri, RRD_FLAG_HIDDEN);
492 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
493 }
494 }
495 }
496
497 inline void rrdinstance_updated_rrdset_flags(RRDSET *st) {
498 rrdinstance_rrdset_not_collected(st);
499
500 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
501 if(unlikely(!ri)) return;
502
503 if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))
504 rrdinstance_set_archived(ri);
505
506 rrdinstance_updated_rrdset_flags_no_action(ri, st);
507
508 rrdinstance_trigger_updates(ri, __FUNCTION__ );
509 }
510
511 ALWAYS_INLINE void rrdinstance_collected_rrdset(RRDSET *st) {
512 if(st->rrdcontexts.collected)
513 return;
514
515 st->rrdcontexts.collected = true;
516
517 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
518 if(unlikely(!ri)) {
519 rrdcontext_updated_rrdset(st);
520 ri = rrdset_get_rrdinstance(st);
521 if(unlikely(!ri))
522 return;
523 }
524
525 rrdinstance_updated_rrdset_flags_no_action(ri, st);
526
527 if(unlikely(ri->internal.collected_metrics_count && !rrd_flag_is_collected(ri)))
528 rrdinstance_set_collected(ri);
529
530 // we use this variable to detect BEGIN/END without SET
531 ri->internal.collected_metrics_count = 0;
532
533 rrdinstance_trigger_updates(ri, __FUNCTION__ );
534 }