context.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "internal.h"
  3. inline const char *rrdcontext_acquired_id(RRDCONTEXT_ACQUIRED *rca) {
  4. RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
  5. return string2str(rc->id);
  6. }
  7. inline bool rrdcontext_acquired_belongs_to_host(RRDCONTEXT_ACQUIRED *rca, RRDHOST *host) {
  8. RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
  9. return rc->rrdhost == host;
  10. }
  11. // ----------------------------------------------------------------------------
  12. // RRDCONTEXT
  13. static void rrdcontext_freez(RRDCONTEXT *rc) {
  14. string_freez(rc->id);
  15. string_freez(rc->title);
  16. string_freez(rc->units);
  17. string_freez(rc->family);
  18. }
  19. static void rrdcontext_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdhost) {
  20. RRDHOST *host = (RRDHOST *)rrdhost;
  21. RRDCONTEXT *rc = (RRDCONTEXT *)value;
  22. rc->rrdhost = host;
  23. rc->flags = rc->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS; // no need for atomics at constructor
  24. if(rc->hub.version) {
  25. // we are loading data from the SQL database
  26. if(rc->version)
  27. error("RRDCONTEXT: context '%s' is already initialized with version %"PRIu64", but it is loaded again from SQL with version %"PRIu64"", string2str(rc->id), rc->version, rc->hub.version);
  28. // IMPORTANT
  29. // replace all string pointers in rc->hub with our own versions
  30. // the originals are coming from a tmp allocation of sqlite
  31. string_freez(rc->id);
  32. rc->id = string_strdupz(rc->hub.id);
  33. rc->hub.id = string2str(rc->id);
  34. string_freez(rc->title);
  35. rc->title = string_strdupz(rc->hub.title);
  36. rc->hub.title = string2str(rc->title);
  37. string_freez(rc->units);
  38. rc->units = string_strdupz(rc->hub.units);
  39. rc->hub.units = string2str(rc->units);
  40. string_freez(rc->family);
  41. rc->family = string_strdupz(rc->hub.family);
  42. rc->hub.family = string2str(rc->family);
  43. rc->chart_type = rrdset_type_id(rc->hub.chart_type);
  44. rc->hub.chart_type = rrdset_type_name(rc->chart_type);
  45. rc->version = rc->hub.version;
  46. rc->priority = rc->hub.priority;
  47. rc->first_time_s = (time_t)rc->hub.first_time_s;
  48. rc->last_time_s = (time_t)rc->hub.last_time_s;
  49. if(rc->hub.deleted || !rc->hub.first_time_s)
  50. rrd_flag_set_deleted(rc, RRD_FLAG_NONE);
  51. else {
  52. if (rc->last_time_s == 0)
  53. rrd_flag_set_collected(rc);
  54. else
  55. rrd_flag_set_archived(rc);
  56. }
  57. rc->flags |= RRD_FLAG_UPDATE_REASON_LOAD_SQL; // no need for atomics at constructor
  58. }
  59. else {
  60. // we are adding this context now for the first time
  61. rc->version = now_realtime_sec();
  62. }
  63. rrdinstances_create_in_rrdcontext(rc);
  64. netdata_mutex_init(&rc->mutex);
  65. // signal the react callback to do the job
  66. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
  67. }
  68. static void rrdcontext_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdhost __maybe_unused) {
  69. RRDCONTEXT *rc = (RRDCONTEXT *)value;
  70. rrdinstances_destroy_from_rrdcontext(rc);
  71. netdata_mutex_destroy(&rc->mutex);
  72. rrdcontext_freez(rc);
  73. }
  74. static bool rrdcontext_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *rrdhost __maybe_unused) {
  75. RRDCONTEXT *rc = (RRDCONTEXT *)old_value;
  76. RRDCONTEXT *rc_new = (RRDCONTEXT *)new_value;
  77. //current rc is not archived, new_rc is archived, don't merge
  78. if (!rrd_flag_is_archived(rc) && rrd_flag_is_archived(rc_new)) {
  79. rrdcontext_freez(rc_new);
  80. return false;
  81. }
  82. rrdcontext_lock(rc);
  83. if(rc->title != rc_new->title) {
  84. STRING *old_title = rc->title;
  85. if (rrd_flag_is_archived(rc) && !rrd_flag_is_archived(rc_new))
  86. rc->title = string_dup(rc_new->title);
  87. else
  88. rc->title = string_2way_merge(rc->title, rc_new->title);
  89. string_freez(old_title);
  90. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
  91. }
  92. if(rc->units != rc_new->units) {
  93. STRING *old_units = rc->units;
  94. rc->units = string_dup(rc_new->units);
  95. string_freez(old_units);
  96. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
  97. }
  98. if(rc->family != rc_new->family) {
  99. STRING *old_family = rc->family;
  100. if (rrd_flag_is_archived(rc) && !rrd_flag_is_archived(rc_new))
  101. rc->family = string_dup(rc_new->family);
  102. else
  103. rc->family = string_2way_merge(rc->family, rc_new->family);
  104. string_freez(old_family);
  105. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
  106. }
  107. if(rc->chart_type != rc_new->chart_type) {
  108. rc->chart_type = rc_new->chart_type;
  109. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
  110. }
  111. if(rc->priority != rc_new->priority) {
  112. rc->priority = rc_new->priority;
  113. rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_METADATA);
  114. }
  115. rrd_flag_set(rc, rc_new->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS); // no need for atomics on rc_new
  116. if(rrd_flag_is_collected(rc) && rrd_flag_is_archived(rc))
  117. rrd_flag_set_collected(rc);
  118. if(rrd_flag_is_updated(rc))
  119. rrd_flag_set(rc, RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT);
  120. rrdcontext_unlock(rc);
  121. // free the resources of the new one
  122. rrdcontext_freez(rc_new);
  123. // the react callback will continue from here
  124. return rrd_flag_is_updated(rc);
  125. }
  126. static void rrdcontext_react_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdhost __maybe_unused) {
  127. RRDCONTEXT *rc = (RRDCONTEXT *)value;
  128. rrdcontext_trigger_updates(rc, __FUNCTION__ );
  129. }
  130. void rrdcontext_trigger_updates(RRDCONTEXT *rc, const char *function) {
  131. if(rrd_flag_is_updated(rc) || !rrd_flag_check(rc, RRD_FLAG_LIVE_RETENTION))
  132. rrdcontext_queue_for_post_processing(rc, function, rc->flags);
  133. }
  134. static void rrdcontext_hub_queue_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *nothing __maybe_unused) {
  135. RRDCONTEXT *rc = context;
  136. rrd_flag_set(rc, RRD_FLAG_QUEUED_FOR_HUB);
  137. rc->queue.queued_ut = now_realtime_usec();
  138. rc->queue.queued_flags = rrd_flags_get(rc);
  139. }
  140. static void rrdcontext_hub_queue_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *nothing __maybe_unused) {
  141. RRDCONTEXT *rc = context;
  142. rrd_flag_clear(rc, RRD_FLAG_QUEUED_FOR_HUB);
  143. }
  144. static bool rrdcontext_hub_queue_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *new_context __maybe_unused, void *nothing __maybe_unused) {
  145. // context and new_context are the same
  146. // we just need to update the timings
  147. RRDCONTEXT *rc = context;
  148. rrd_flag_set(rc, RRD_FLAG_QUEUED_FOR_HUB);
  149. rc->queue.queued_ut = now_realtime_usec();
  150. rc->queue.queued_flags |= rrd_flags_get(rc);
  151. return true;
  152. }
  153. static void rrdcontext_post_processing_queue_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *nothing __maybe_unused) {
  154. RRDCONTEXT *rc = context;
  155. rrd_flag_set(rc, RRD_FLAG_QUEUED_FOR_PP);
  156. rc->pp.queued_flags = rc->flags;
  157. rc->pp.queued_ut = now_realtime_usec();
  158. }
  159. static void rrdcontext_post_processing_queue_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *nothing __maybe_unused) {
  160. RRDCONTEXT *rc = context;
  161. rrd_flag_clear(rc, RRD_FLAG_QUEUED_FOR_PP);
  162. rc->pp.dequeued_ut = now_realtime_usec();
  163. }
  164. static bool rrdcontext_post_processing_queue_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *context, void *new_context __maybe_unused, void *nothing __maybe_unused) {
  165. RRDCONTEXT *rc = context;
  166. bool changed = false;
  167. if(!(rc->flags & RRD_FLAG_QUEUED_FOR_PP)) {
  168. rrd_flag_set(rc, RRD_FLAG_QUEUED_FOR_PP);
  169. changed = true;
  170. }
  171. if(rc->pp.queued_flags != rc->flags) {
  172. rc->pp.queued_flags |= rc->flags;
  173. changed = true;
  174. }
  175. return changed;
  176. }
  177. void rrdhost_create_rrdcontexts(RRDHOST *host) {
  178. if(unlikely(!host)) return;
  179. if(likely(host->rrdctx.contexts)) return;
  180. host->rrdctx.contexts = dictionary_create_advanced(
  181. DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
  182. &dictionary_stats_category_rrdcontext, sizeof(RRDCONTEXT));
  183. dictionary_register_insert_callback(host->rrdctx.contexts, rrdcontext_insert_callback, host);
  184. dictionary_register_delete_callback(host->rrdctx.contexts, rrdcontext_delete_callback, host);
  185. dictionary_register_conflict_callback(host->rrdctx.contexts, rrdcontext_conflict_callback, host);
  186. dictionary_register_react_callback(host->rrdctx.contexts, rrdcontext_react_callback, host);
  187. host->rrdctx.hub_queue = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE, &dictionary_stats_category_rrdcontext, 0);
  188. dictionary_register_insert_callback(host->rrdctx.hub_queue, rrdcontext_hub_queue_insert_callback, NULL);
  189. dictionary_register_delete_callback(host->rrdctx.hub_queue, rrdcontext_hub_queue_delete_callback, NULL);
  190. dictionary_register_conflict_callback(host->rrdctx.hub_queue, rrdcontext_hub_queue_conflict_callback, NULL);
  191. host->rrdctx.pp_queue = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_VALUE_LINK_DONT_CLONE, &dictionary_stats_category_rrdcontext, 0);
  192. dictionary_register_insert_callback(host->rrdctx.pp_queue, rrdcontext_post_processing_queue_insert_callback, NULL);
  193. dictionary_register_delete_callback(host->rrdctx.pp_queue, rrdcontext_post_processing_queue_delete_callback, NULL);
  194. dictionary_register_conflict_callback(host->rrdctx.pp_queue, rrdcontext_post_processing_queue_conflict_callback, NULL);
  195. }
  196. void rrdhost_destroy_rrdcontexts(RRDHOST *host) {
  197. if(unlikely(!host)) return;
  198. if(unlikely(!host->rrdctx.contexts)) return;
  199. DICTIONARY *old;
  200. if(host->rrdctx.hub_queue) {
  201. old = host->rrdctx.hub_queue;
  202. host->rrdctx.hub_queue = NULL;
  203. RRDCONTEXT *rc;
  204. dfe_start_write(old, rc) {
  205. dictionary_del(old, string2str(rc->id));
  206. }
  207. dfe_done(rc);
  208. dictionary_destroy(old);
  209. }
  210. if(host->rrdctx.pp_queue) {
  211. old = host->rrdctx.pp_queue;
  212. host->rrdctx.pp_queue = NULL;
  213. RRDCONTEXT *rc;
  214. dfe_start_write(old, rc) {
  215. dictionary_del(old, string2str(rc->id));
  216. }
  217. dfe_done(rc);
  218. dictionary_destroy(old);
  219. }
  220. old = host->rrdctx.contexts;
  221. host->rrdctx.contexts = NULL;
  222. dictionary_destroy(old);
  223. }