rrddim.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #define NETDATA_RRD_INTERNALS
  3. #include "rrd.h"
  4. #include "storage_engine.h"
  5. void rrddim_metadata_updated(RRDDIM *rd) {
  6. rrdcontext_updated_rrddim(rd);
  7. rrdset_metadata_updated(rd->rrdset);
  8. }
  9. // ----------------------------------------------------------------------------
  10. // RRDDIM index
  11. struct rrddim_constructor {
  12. RRDSET *st;
  13. const char *id;
  14. const char *name;
  15. collected_number multiplier;
  16. collected_number divisor;
  17. RRD_ALGORITHM algorithm;
  18. RRD_MEMORY_MODE memory_mode;
  19. enum {
  20. RRDDIM_REACT_NONE = 0,
  21. RRDDIM_REACT_NEW = (1 << 0),
  22. RRDDIM_REACT_UPDATED = (1 << 2),
  23. } react_action;
  24. };
  25. // isolated call to appear
  26. // separate in statistics
  27. static void *rrddim_alloc_db(size_t entries) {
  28. return callocz(entries, sizeof(storage_number));
  29. }
  30. static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddim, void *constructor_data) {
  31. struct rrddim_constructor *ctr = constructor_data;
  32. RRDDIM *rd = rrddim;
  33. RRDSET *st = ctr->st;
  34. RRDHOST *host = st->rrdhost;
  35. rd->flags = RRDDIM_FLAG_NONE;
  36. rd->id = string_strdupz(ctr->id);
  37. rd->name = (ctr->name && *ctr->name)?rrd_string_strdupz(ctr->name):string_dup(rd->id);
  38. rd->algorithm = ctr->algorithm;
  39. rd->multiplier = ctr->multiplier;
  40. rd->divisor = ctr->divisor;
  41. if(!rd->divisor) rd->divisor = 1;
  42. rd->rrdset = st;
  43. rd->rrdpush.sender.dim_slot = __atomic_add_fetch(&st->rrdpush.sender.dim_last_slot_used, 1, __ATOMIC_RELAXED);
  44. if(rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST))
  45. rd->collector.counter = 1;
  46. if(ctr->memory_mode == RRD_MEMORY_MODE_RAM) {
  47. size_t entries = st->db.entries;
  48. if(!entries) entries = 5;
  49. rd->db.data = netdata_mmap(NULL, entries * sizeof(storage_number), MAP_PRIVATE, 1, false, NULL);
  50. if(!rd->db.data) {
  51. netdata_log_info("Failed to use memory mode ram for chart '%s', dimension '%s', falling back to alloc", rrdset_name(st), rrddim_name(rd));
  52. ctr->memory_mode = RRD_MEMORY_MODE_ALLOC;
  53. }
  54. else {
  55. rd->db.memsize = entries * sizeof(storage_number);
  56. __atomic_add_fetch(&rrddim_db_memory_size, rd->db.memsize, __ATOMIC_RELAXED);
  57. }
  58. }
  59. if(ctr->memory_mode == RRD_MEMORY_MODE_ALLOC || ctr->memory_mode == RRD_MEMORY_MODE_NONE) {
  60. size_t entries = st->db.entries;
  61. if(entries < 5) entries = 5;
  62. rd->db.data = rrddim_alloc_db(entries);
  63. rd->db.memsize = entries * sizeof(storage_number);
  64. __atomic_add_fetch(&rrddim_db_memory_size, rd->db.memsize, __ATOMIC_RELAXED);
  65. }
  66. rd->rrd_memory_mode = ctr->memory_mode;
  67. if (unlikely(rrdcontext_find_dimension_uuid(st, rrddim_id(rd), &(rd->metric_uuid))))
  68. uuid_generate(rd->metric_uuid);
  69. // initialize the db tiers
  70. {
  71. size_t initialized = 0;
  72. for(size_t tier = 0; tier < storage_tiers ; tier++) {
  73. STORAGE_ENGINE *eng = host->db[tier].eng;
  74. rd->tiers[tier].seb = eng->seb;
  75. rd->tiers[tier].tier_grouping = host->db[tier].tier_grouping;
  76. rd->tiers[tier].smh = eng->api.metric_get_or_create(rd, host->db[tier].si);
  77. storage_point_unset(rd->tiers[tier].virtual_point);
  78. initialized++;
  79. // internal_error(true, "TIER GROUPING of chart '%s', dimension '%s' for tier %d is set to %d", rd->rrdset->name, rd->name, tier, rd->tiers[tier]->tier_grouping);
  80. }
  81. if(!initialized)
  82. netdata_log_error("Failed to initialize all db tiers for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
  83. if(!rd->tiers[0].smh)
  84. netdata_log_error("Failed to initialize the first db tier for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
  85. }
  86. // initialize data collection for all tiers
  87. {
  88. size_t initialized = 0;
  89. for (size_t tier = 0; tier < storage_tiers; tier++) {
  90. if (rd->tiers[tier].smh) {
  91. rd->tiers[tier].sch =
  92. storage_metric_store_init(rd->tiers[tier].seb, rd->tiers[tier].smh, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->smg[tier]);
  93. initialized++;
  94. }
  95. }
  96. if(!initialized)
  97. netdata_log_error("Failed to initialize data collection for all db tiers for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
  98. }
  99. if(rrdset_number_of_dimensions(st) != 0) {
  100. RRDDIM *td;
  101. dfe_start_write(st->rrddim_root_index, td) {
  102. if(td) break;
  103. }
  104. dfe_done(td);
  105. if(td && (td->algorithm != rd->algorithm || ABS(td->multiplier) != ABS(rd->multiplier) || ABS(td->divisor) != ABS(rd->divisor))) {
  106. if(!rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) {
  107. #ifdef NETDATA_INTERNAL_CHECKS
  108. netdata_log_info("Dimension '%s' added on chart '%s' of host '%s' is not homogeneous to other dimensions already "
  109. "present (algorithm is '%s' vs '%s', multiplier is %d vs %d, "
  110. "divisor is %d vs %d).",
  111. rrddim_name(rd),
  112. rrdset_name(st),
  113. rrdhost_hostname(host),
  114. rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(td->algorithm),
  115. rd->multiplier, td->multiplier,
  116. rd->divisor, td->divisor
  117. );
  118. #endif
  119. rrdset_flag_set(st, RRDSET_FLAG_HETEROGENEOUS);
  120. }
  121. }
  122. }
  123. rrddim_flag_set(rd, RRDDIM_FLAG_PENDING_HEALTH_INITIALIZATION);
  124. rrdset_flag_set(rd->rrdset, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION);
  125. rrdhost_flag_set(rd->rrdset->rrdhost, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION);
  126. // let the chart resync
  127. rrdset_flag_set(st, RRDSET_FLAG_SYNC_CLOCK);
  128. ml_dimension_new(rd);
  129. ctr->react_action = RRDDIM_REACT_NEW;
  130. internal_error(false, "RRDDIM: inserted dimension '%s' of chart '%s' of host '%s'",
  131. rrddim_name(rd), rrdset_name(st), rrdhost_hostname(st->rrdhost));
  132. }
  133. bool rrddim_finalize_collection_and_check_retention(RRDDIM *rd) {
  134. size_t tiers_available = 0, tiers_said_no_retention = 0;
  135. for(size_t tier = 0; tier < storage_tiers ;tier++) {
  136. if(!rd->tiers[tier].sch)
  137. continue;
  138. tiers_available++;
  139. if(storage_engine_store_finalize(rd->tiers[tier].sch))
  140. tiers_said_no_retention++;
  141. rd->tiers[tier].sch = NULL;
  142. }
  143. // return true if the dimension has retention in the db
  144. return (!tiers_said_no_retention || tiers_available > tiers_said_no_retention);
  145. }
  146. static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddim, void *rrdset) {
  147. RRDDIM *rd = rrddim;
  148. RRDSET *st = rrdset;
  149. RRDHOST *host = st->rrdhost;
  150. internal_error(false, "RRDDIM: deleting dimension '%s' of chart '%s' of host '%s'",
  151. rrddim_name(rd), rrdset_name(st), rrdhost_hostname(host));
  152. rrdcontext_removed_rrddim(rd);
  153. ml_dimension_delete(rd);
  154. netdata_log_debug(D_RRD_CALLS, "rrddim_free() %s.%s", rrdset_name(st), rrddim_name(rd));
  155. if (!rrddim_finalize_collection_and_check_retention(rd) && rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
  156. /* This metric has no data and no references */
  157. metaqueue_delete_dimension_uuid(&rd->metric_uuid);
  158. }
  159. rrddimvar_delete_all(rd);
  160. for(size_t tier = 0; tier < storage_tiers ;tier++) {
  161. if(!rd->tiers[tier].smh) continue;
  162. STORAGE_ENGINE* eng = host->db[tier].eng;
  163. eng->api.metric_release(rd->tiers[tier].smh);
  164. rd->tiers[tier].smh = NULL;
  165. }
  166. if(rd->db.data) {
  167. __atomic_sub_fetch(&rrddim_db_memory_size, rd->db.memsize, __ATOMIC_RELAXED);
  168. if(rd->rrd_memory_mode == RRD_MEMORY_MODE_RAM)
  169. netdata_munmap(rd->db.data, rd->db.memsize);
  170. else
  171. freez(rd->db.data);
  172. }
  173. string_freez(rd->id);
  174. string_freez(rd->name);
  175. }
  176. static bool rrddim_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddim, void *new_rrddim, void *constructor_data) {
  177. (void)new_rrddim; // it is NULL
  178. struct rrddim_constructor *ctr = constructor_data;
  179. RRDDIM *rd = rrddim;
  180. RRDSET *st = ctr->st;
  181. ctr->react_action = RRDDIM_REACT_NONE;
  182. int rc = rrddim_reset_name(st, rd, ctr->name);
  183. rc += rrddim_set_algorithm(st, rd, ctr->algorithm);
  184. rc += rrddim_set_multiplier(st, rd, ctr->multiplier);
  185. rc += rrddim_set_divisor(st, rd, ctr->divisor);
  186. for(size_t tier = 0; tier < storage_tiers ;tier++) {
  187. if (!rd->tiers[tier].sch)
  188. rd->tiers[tier].sch =
  189. storage_metric_store_init(rd->tiers[tier].seb, rd->tiers[tier].smh, st->rrdhost->db[tier].tier_grouping * st->update_every, rd->rrdset->smg[tier]);
  190. }
  191. if(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
  192. rrddim_flag_clear(rd, RRDDIM_FLAG_ARCHIVED);
  193. rrddim_flag_set(rd, RRDDIM_FLAG_PENDING_HEALTH_INITIALIZATION);
  194. rrdset_flag_set(rd->rrdset, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION);
  195. rrdhost_flag_set(rd->rrdset->rrdhost, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION);
  196. }
  197. if(unlikely(rc))
  198. ctr->react_action = RRDDIM_REACT_UPDATED;
  199. return ctr->react_action == RRDDIM_REACT_UPDATED;
  200. }
  201. static void rrddim_react_callback(const DICTIONARY_ITEM *item __maybe_unused, void *rrddim, void *constructor_data) {
  202. struct rrddim_constructor *ctr = constructor_data;
  203. RRDDIM *rd = rrddim;
  204. RRDSET *st = ctr->st;
  205. if(ctr->react_action & (RRDDIM_REACT_UPDATED | RRDDIM_REACT_NEW)) {
  206. rrddim_flag_set(rd, RRDDIM_FLAG_METADATA_UPDATE);
  207. rrdhost_flag_set(rd->rrdset->rrdhost, RRDHOST_FLAG_METADATA_UPDATE);
  208. }
  209. if(ctr->react_action == RRDDIM_REACT_UPDATED) {
  210. // the chart needs to be updated to the parent
  211. rrdset_flag_set(st, RRDSET_FLAG_SYNC_CLOCK);
  212. }
  213. rrddim_metadata_updated(rd);
  214. }
  215. size_t rrddim_size(void) {
  216. return sizeof(RRDDIM) + storage_tiers * sizeof(struct rrddim_tier);
  217. }
  218. void rrddim_index_init(RRDSET *st) {
  219. if(!st->rrddim_root_index) {
  220. st->rrddim_root_index = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
  221. &dictionary_stats_category_rrdset_rrddim, rrddim_size());
  222. dictionary_register_insert_callback(st->rrddim_root_index, rrddim_insert_callback, NULL);
  223. dictionary_register_conflict_callback(st->rrddim_root_index, rrddim_conflict_callback, NULL);
  224. dictionary_register_delete_callback(st->rrddim_root_index, rrddim_delete_callback, st);
  225. dictionary_register_react_callback(st->rrddim_root_index, rrddim_react_callback, st);
  226. }
  227. }
  228. void rrddim_index_destroy(RRDSET *st) {
  229. dictionary_destroy(st->rrddim_root_index);
  230. st->rrddim_root_index = NULL;
  231. }
  232. static inline RRDDIM *rrddim_index_find(RRDSET *st, const char *id) {
  233. return dictionary_get(st->rrddim_root_index, id);
  234. }
  235. // ----------------------------------------------------------------------------
  236. // RRDDIM - find a dimension
  237. inline RRDDIM *rrddim_find(RRDSET *st, const char *id) {
  238. netdata_log_debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", rrdset_name(st), id);
  239. return rrddim_index_find(st, id);
  240. }
  241. inline RRDDIM_ACQUIRED *rrddim_find_and_acquire(RRDSET *st, const char *id) {
  242. netdata_log_debug(D_RRD_CALLS, "rrddim_find_and_acquire() for chart %s, dimension %s", rrdset_name(st), id);
  243. return (RRDDIM_ACQUIRED *)dictionary_get_and_acquire_item(st->rrddim_root_index, id);
  244. }
  245. RRDDIM *rrddim_acquired_to_rrddim(RRDDIM_ACQUIRED *rda) {
  246. if(unlikely(!rda))
  247. return NULL;
  248. return (RRDDIM *) dictionary_acquired_item_value((const DICTIONARY_ITEM *)rda);
  249. }
  250. void rrddim_acquired_release(RRDDIM_ACQUIRED *rda) {
  251. if(unlikely(!rda))
  252. return;
  253. RRDDIM *rd = rrddim_acquired_to_rrddim(rda);
  254. dictionary_acquired_item_release(rd->rrdset->rrddim_root_index, (const DICTIONARY_ITEM *)rda);
  255. }
  256. // This will not return dimensions that are archived
  257. RRDDIM *rrddim_find_active(RRDSET *st, const char *id) {
  258. RRDDIM *rd = rrddim_find(st, id);
  259. if (unlikely(rd && rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)))
  260. return NULL;
  261. return rd;
  262. }
  263. // ----------------------------------------------------------------------------
  264. // RRDDIM rename a dimension
  265. inline int rrddim_reset_name(RRDSET *st __maybe_unused, RRDDIM *rd, const char *name) {
  266. if(unlikely(!name || !*name || !strcmp(rrddim_name(rd), name)))
  267. return 0;
  268. netdata_log_debug(D_RRD_CALLS, "rrddim_reset_name() from %s.%s to %s.%s", rrdset_name(st), rrddim_name(rd), rrdset_name(st), name);
  269. STRING *old = rd->name;
  270. rd->name = rrd_string_strdupz(name);
  271. string_freez(old);
  272. rrddimvar_rename_all(rd);
  273. rrddim_metadata_updated(rd);
  274. return 1;
  275. }
  276. inline int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm) {
  277. if(unlikely(rd->algorithm == algorithm))
  278. return 0;
  279. netdata_log_debug(D_RRD_CALLS, "Updating algorithm of dimension '%s/%s' from %s to %s", rrdset_id(st), rrddim_name(rd), rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm));
  280. rd->algorithm = algorithm;
  281. rrddim_metadata_updated(rd);
  282. rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
  283. rrdcontext_updated_rrddim_algorithm(rd);
  284. return 1;
  285. }
  286. inline int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, int32_t multiplier) {
  287. if(unlikely(rd->multiplier == multiplier))
  288. return 0;
  289. netdata_log_debug(D_RRD_CALLS, "Updating multiplier of dimension '%s/%s' from %d to %d",
  290. rrdset_id(st), rrddim_name(rd), rd->multiplier, multiplier);
  291. rd->multiplier = multiplier;
  292. rrddim_metadata_updated(rd);
  293. rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
  294. rrdcontext_updated_rrddim_multiplier(rd);
  295. return 1;
  296. }
  297. inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, int32_t divisor) {
  298. if(unlikely(rd->divisor == divisor))
  299. return 0;
  300. netdata_log_debug(D_RRD_CALLS, "Updating divisor of dimension '%s/%s' from %d to %d",
  301. rrdset_id(st), rrddim_name(rd), rd->divisor, divisor);
  302. rd->divisor = divisor;
  303. rrddim_metadata_updated(rd);
  304. rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
  305. rrdcontext_updated_rrddim_divisor(rd);
  306. return 1;
  307. }
  308. // ----------------------------------------------------------------------------
  309. time_t rrddim_last_entry_s_of_tier(RRDDIM *rd, size_t tier) {
  310. if(unlikely(tier > storage_tiers || !rd->tiers[tier].smh))
  311. return 0;
  312. return storage_engine_latest_time_s(rd->tiers[tier].seb, rd->tiers[tier].smh);
  313. }
  314. // get the timestamp of the last entry in the round-robin database
  315. time_t rrddim_last_entry_s(RRDDIM *rd) {
  316. time_t latest_time_s = rrddim_last_entry_s_of_tier(rd, 0);
  317. for(size_t tier = 1; tier < storage_tiers ;tier++) {
  318. if(unlikely(!rd->tiers[tier].smh)) continue;
  319. time_t t = rrddim_last_entry_s_of_tier(rd, tier);
  320. if(t > latest_time_s)
  321. latest_time_s = t;
  322. }
  323. return latest_time_s;
  324. }
  325. time_t rrddim_first_entry_s_of_tier(RRDDIM *rd, size_t tier) {
  326. if(unlikely(tier > storage_tiers || !rd->tiers[tier].smh))
  327. return 0;
  328. return storage_engine_oldest_time_s(rd->tiers[tier].seb, rd->tiers[tier].smh);
  329. }
  330. time_t rrddim_first_entry_s(RRDDIM *rd) {
  331. time_t oldest_time_s = 0;
  332. for(size_t tier = 0; tier < storage_tiers ;tier++) {
  333. time_t t = rrddim_first_entry_s_of_tier(rd, tier);
  334. if(t != 0 && (oldest_time_s == 0 || t < oldest_time_s))
  335. oldest_time_s = t;
  336. }
  337. return oldest_time_s;
  338. }
  339. RRDDIM *rrddim_add_custom(RRDSET *st
  340. , const char *id
  341. , const char *name
  342. , collected_number multiplier
  343. , collected_number divisor
  344. , RRD_ALGORITHM algorithm
  345. , RRD_MEMORY_MODE memory_mode
  346. ) {
  347. struct rrddim_constructor tmp = {
  348. .st = st,
  349. .id = id,
  350. .name = name,
  351. .multiplier = multiplier,
  352. .divisor = divisor,
  353. .algorithm = algorithm,
  354. .memory_mode = memory_mode,
  355. };
  356. RRDDIM *rd = dictionary_set_advanced(st->rrddim_root_index, tmp.id, -1, NULL, rrddim_size(), &tmp);
  357. return(rd);
  358. }
  359. // ----------------------------------------------------------------------------
  360. // RRDDIM remove / free a dimension
  361. void rrddim_free(RRDSET *st, RRDDIM *rd) {
  362. dictionary_del(st->rrddim_root_index, string2str(rd->id));
  363. }
  364. // ----------------------------------------------------------------------------
  365. // RRDDIM - set dimension options
  366. int rrddim_hide(RRDSET *st, const char *id) {
  367. netdata_log_debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", rrdset_name(st), id);
  368. RRDHOST *host = st->rrdhost;
  369. RRDDIM *rd = rrddim_find(st, id);
  370. if(unlikely(!rd)) {
  371. netdata_log_error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
  372. return 1;
  373. }
  374. if (!rrddim_flag_check(rd, RRDDIM_FLAG_META_HIDDEN)) {
  375. rrddim_flag_set(rd, RRDDIM_FLAG_META_HIDDEN | RRDDIM_FLAG_METADATA_UPDATE);
  376. rrdhost_flag_set(rd->rrdset->rrdhost, RRDHOST_FLAG_METADATA_UPDATE);
  377. }
  378. rrddim_option_set(rd, RRDDIM_OPTION_HIDDEN);
  379. rrdcontext_updated_rrddim_flags(rd);
  380. return 0;
  381. }
  382. int rrddim_unhide(RRDSET *st, const char *id) {
  383. netdata_log_debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", rrdset_name(st), id);
  384. RRDHOST *host = st->rrdhost;
  385. RRDDIM *rd = rrddim_find(st, id);
  386. if(unlikely(!rd)) {
  387. netdata_log_error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
  388. return 1;
  389. }
  390. if (rrddim_flag_check(rd, RRDDIM_FLAG_META_HIDDEN)) {
  391. rrddim_flag_clear(rd, RRDDIM_FLAG_META_HIDDEN);
  392. rrddim_flag_set(rd, RRDDIM_FLAG_METADATA_UPDATE);
  393. rrdhost_flag_set(rd->rrdset->rrdhost, RRDHOST_FLAG_METADATA_UPDATE);
  394. }
  395. rrddim_option_clear(rd, RRDDIM_OPTION_HIDDEN);
  396. rrdcontext_updated_rrddim_flags(rd);
  397. return 0;
  398. }
  399. inline void rrddim_is_obsolete___safe_from_collector_thread(RRDSET *st, RRDDIM *rd) {
  400. netdata_log_debug(D_RRD_CALLS, "rrddim_is_obsolete___safe_from_collector_thread() for chart %s, dimension %s", rrdset_name(st), rrddim_name(rd));
  401. if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))) {
  402. netdata_log_info("Cannot obsolete already archived dimension %s from chart %s", rrddim_name(rd), rrdset_name(st));
  403. return;
  404. }
  405. rrddim_flag_set(rd, RRDDIM_FLAG_OBSOLETE);
  406. rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS);
  407. rrdhost_flag_set(st->rrdhost, RRDHOST_FLAG_PENDING_OBSOLETE_DIMENSIONS);
  408. rrdcontext_updated_rrddim_flags(rd);
  409. }
  410. inline void rrddim_isnot_obsolete___safe_from_collector_thread(RRDSET *st __maybe_unused, RRDDIM *rd) {
  411. netdata_log_debug(D_RRD_CALLS, "rrddim_isnot_obsolete___safe_from_collector_thread() for chart %s, dimension %s", rrdset_name(st), rrddim_name(rd));
  412. rrddim_flag_clear(rd, RRDDIM_FLAG_OBSOLETE);
  413. rrdcontext_updated_rrddim_flags(rd);
  414. }
  415. // ----------------------------------------------------------------------------
  416. // RRDDIM - collect values for a dimension
  417. inline collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value) {
  418. struct timeval now;
  419. now_realtime_timeval(&now);
  420. return rrddim_timed_set_by_pointer(st, rd, now, value);
  421. }
  422. collected_number rrddim_timed_set_by_pointer(RRDSET *st __maybe_unused, RRDDIM *rd, struct timeval collected_time, collected_number value) {
  423. netdata_log_debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, rrdset_name(st), rrddim_name(rd), value);
  424. rd->collector.last_collected_time = collected_time;
  425. rd->collector.collected_value = value;
  426. rrddim_set_updated(rd);
  427. rd->collector.counter++;
  428. collected_number v = (value >= 0) ? value : -value;
  429. if (unlikely(v > rd->collector.collected_value_max))
  430. rd->collector.collected_value_max = v;
  431. return rd->collector.last_collected_value;
  432. }
  433. collected_number rrddim_set(RRDSET *st, const char *id, collected_number value) {
  434. RRDHOST *host = st->rrdhost;
  435. RRDDIM *rd = rrddim_find(st, id);
  436. if(unlikely(!rd)) {
  437. netdata_log_error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
  438. return 0;
  439. }
  440. return rrddim_set_by_pointer(st, rd, value);
  441. }