master
c 889 lines 29.4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "rrd.h"
4
5 #if RRD_STORAGE_TIERS != 5
6 #error RRD_STORAGE_TIERS is not 5 - you need to update the grouping iterations per tier
7 #endif
8
9 RRDHOST *localhost = NULL;
10 netdata_rwlock_t rrd_rwlock;
11
12 static void __attribute__((constructor)) init_lock(void) {
13 netdata_rwlock_init(&rrd_rwlock);
14 }
15
16 static void __attribute__((destructor)) destroy_lock(void) {
17 netdata_rwlock_destroy(&rrd_rwlock);
18 }
19
20 RRDHOST *rrdhost_find_by_node_id(const char *node_id) {
21
22 ND_UUID node_uuid;
23 if (unlikely(!node_id || uuid_parse(node_id, node_uuid.uuid)))
24 return NULL;
25
26 RRDHOST *host, *ret = NULL;
27 dfe_start_read(rrdhost_root_index, host) {
28 if (UUIDeq(host->node_id, node_uuid)) {
29 ret = host;
30 break;
31 }
32 }
33 dfe_done(host);
34
35 return ret;
36 }
37
38 RRDHOST *rrdhost_find_by_hostname(const char *hostname) {
39 if(strcmp(hostname, "localhost") == 0)
40 return localhost;
41
42 STRING *name = string_strdupz(hostname);
43
44 RRDHOST *host, *ret = NULL;
45 dfe_start_read(rrdhost_root_index, host) {
46 if (host->hostname == name) {
47 ret = host;
48 break;
49 }
50 }
51 dfe_done(host);
52
53 string_freez(name);
54
55 return ret;
56 }
57
58 // ----------------------------------------------------------------------------
59 // RRDHOST indexes management
60
61 DICTIONARY *rrdhost_root_index = NULL;
62
63 void rrdhost_init() {
64 if(unlikely(!rrdhost_root_index)) {
65 rrdhost_root_index = dictionary_create_advanced(
66 DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_DONT_OVERWRITE_VALUE,
67 &dictionary_stats_category_rrdhost, 0);
68 }
69 }
70
71 RRDHOST_ACQUIRED *rrdhost_find_and_acquire(const char *machine_guid) {
72 return (RRDHOST_ACQUIRED *)dictionary_get_and_acquire_item(rrdhost_root_index, machine_guid);
73 }
74
75 RRDHOST *rrdhost_acquired_to_rrdhost(RRDHOST_ACQUIRED *rha) {
76 if(unlikely(!rha))
77 return NULL;
78
79 return (RRDHOST *) dictionary_acquired_item_value((const DICTIONARY_ITEM *)rha);
80 }
81
82 void rrdhost_acquired_release(RRDHOST_ACQUIRED *rha) {
83 if(unlikely(!rha))
84 return;
85
86 dictionary_acquired_item_release(rrdhost_root_index, (const DICTIONARY_ITEM *)rha);
87 }
88
89 // ----------------------------------------------------------------------------
90 // RRDHOST index by UUID
91
92 inline size_t rrdhost_hosts_available(void) {
93 return dictionary_entries(rrdhost_root_index);
94 }
95
96 inline RRDHOST *rrdhost_find_by_guid(const char *guid) {
97 return dictionary_get(rrdhost_root_index, guid);
98 }
99
100 static inline RRDHOST *rrdhost_index_add_by_guid(RRDHOST *host) {
101 return dictionary_set(rrdhost_root_index, host->machine_guid, host, sizeof(RRDHOST));
102 }
103
104 static void rrdhost_index_del_by_guid(RRDHOST *host) {
105 RRDHOST *t = rrdhost_find_by_guid(host->machine_guid);
106 if(t == host) {
107 if (!dictionary_del(rrdhost_root_index, host->machine_guid))
108 nd_log(
109 NDLS_DAEMON, NDLP_NOTICE,
110 "RRDHOST: failed to delete machine guid '%s' from index",
111 host->machine_guid);
112 }
113 else
114 nd_log(NDLS_DAEMON, NDLP_NOTICE,
115 "RRDHOST: failed to delete machine guid '%s' from index, not found",
116 host->machine_guid);
117 }
118
119 // ----------------------------------------------------------------------------
120 // RRDHOST - internal helpers
121
122 static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) {
123 if(unlikely(hostname && !*hostname)) hostname = NULL;
124
125 if(host->hostname && hostname && !strcmp(rrdhost_hostname(host), hostname))
126 return;
127
128 STRING *old = host->hostname;
129 host->hostname = string_strdupz(hostname?hostname:"localhost");
130 string_freez(old);
131 }
132
133 static inline void rrdhost_init_os(RRDHOST *host, const char *os) {
134 if(host->os && os && !strcmp(rrdhost_os(host), os))
135 return;
136
137 STRING *old = host->os;
138 host->os = string_strdupz(os?os:"unknown");
139 string_freez(old);
140 }
141
142 // Caller must hold rrdhost_update_lock (or be in single-threaded host creation).
143 // Returns true if anything actually changed.
144 static inline bool rrdhost_init_timezone(RRDHOST *host, const char *timezone, const char *abbrev_timezone, int32_t utc_offset) {
145 const char *cur_tz = host->timezone ? string2str(host->timezone) : NULL;
146 const char *cur_abbrev = host->abbrev_timezone ? string2str(host->abbrev_timezone) : NULL;
147
148 if (cur_tz && timezone && !strcmp(cur_tz, timezone) &&
149 cur_abbrev && abbrev_timezone && !strcmp(cur_abbrev, abbrev_timezone) &&
150 host->utc_offset == utc_offset)
151 return false;
152
153 STRING *old = host->timezone;
154 host->timezone = string_strdupz((timezone && *timezone)?timezone:"unknown");
155 string_freez(old);
156
157 old = (void *)host->abbrev_timezone;
158 host->abbrev_timezone = string_strdupz((abbrev_timezone && *abbrev_timezone) ? abbrev_timezone : "UTC");
159 string_freez(old);
160
161 host->utc_offset = utc_offset;
162 return true;
163 }
164
165 void set_host_properties(RRDHOST *host, int update_every,
166 RRD_DB_MODE memory_mode,
167 const char *registry_hostname, const char *os, const char *tzone,
168 const char *abbrev_tzone, int32_t utc_offset, const char *prog_name,
169 const char *prog_version)
170 {
171
172 host->rrd_update_every = update_every;
173 host->rrd_memory_mode = memory_mode;
174
175 rrdhost_init_os(host, os);
176 rrdhost_init_timezone(host, tzone, abbrev_tzone, utc_offset);
177
178 host->program_name = string_strdupz((prog_name && *prog_name) ? prog_name : "unknown");
179 host->program_version = string_strdupz((prog_version && *prog_version) ? prog_version : "unknown");
180 host->registry_hostname = string_strdupz((registry_hostname && *registry_hostname) ? registry_hostname : rrdhost_hostname(host));
181 }
182
183 bool rrdhost_update_timezone(RRDHOST *host, const char *timezone, const char *abbrev_timezone, int32_t utc_offset) {
184 spinlock_lock(&host->rrdhost_update_lock);
185 bool changed = rrdhost_init_timezone(host, timezone, abbrev_timezone, utc_offset);
186 spinlock_unlock(&host->rrdhost_update_lock);
187
188 if (changed)
189 rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_INFO | RRDHOST_FLAG_METADATA_UPDATE);
190
191 return changed;
192 }
193
194 RRDHOST_TZ rrdhost_tz_get(RRDHOST *host) {
195 RRDHOST_TZ tz;
196 spinlock_lock(&host->rrdhost_update_lock);
197 tz.timezone = strdupz(host->timezone ? string2str(host->timezone) : "unknown");
198 tz.abbrev_timezone = strdupz(host->abbrev_timezone ? string2str(host->abbrev_timezone) : "UTC");
199 tz.utc_offset = host->utc_offset;
200 spinlock_unlock(&host->rrdhost_update_lock);
201 return tz;
202 }
203
204 void rrdhost_tz_free(RRDHOST_TZ *tz) {
205 freez(tz->timezone);
206 freez(tz->abbrev_timezone);
207 tz->timezone = NULL;
208 tz->abbrev_timezone = NULL;
209 tz->utc_offset = 0;
210 }
211
212 // ----------------------------------------------------------------------------
213 // RRDHOST - add a host
214
215 #ifdef ENABLE_DBENGINE
216 //
217 // true on success
218 //
219 static bool create_dbengine_directory(RRDHOST *host, const char *dbenginepath)
220 {
221 int ret = mkdir(dbenginepath, 0775);
222 if (ret != 0 && errno != EEXIST) {
223 nd_log(NDLS_DAEMON, NDLP_CRIT, "Host '%s': cannot create directory '%s'", rrdhost_hostname(host), dbenginepath);
224 return false;
225 }
226 return true;
227 }
228
229 static RRDHOST *prepare_host_for_unittest(RRDHOST *host)
230 {
231 char dbenginepath[FILENAME_MAX + 1];
232
233 if (host->cache_dir)
234 freez(host->cache_dir);
235
236 snprintfz(dbenginepath, FILENAME_MAX, "%s/%s", netdata_configured_cache_dir, host->machine_guid);
237 host->cache_dir = strdupz(dbenginepath);
238
239 int ret = 0;
240
241 bool initialized;
242 if ((initialized = create_dbengine_directory(host, dbenginepath))) {
243 snprintfz(dbenginepath, FILENAME_MAX, "%s/dbengine", host->cache_dir);
244
245 if ((initialized = create_dbengine_directory(host, dbenginepath))) {
246 host->db[0].mode = RRD_DB_MODE_DBENGINE;
247 host->db[0].eng = storage_engine_get(host->db[0].mode);
248 host->db[0].tier_grouping = get_tier_grouping(0);
249
250 ret = rrdeng_init(
251 (struct rrdengine_instance **)&host->db[0].si,
252 dbenginepath,
253 default_rrdeng_disk_quota_mb,
254 0,
255 0); // may fail here for legacy dbengine initialization
256
257 initialized = (ret == 0);
258
259 if (initialized)
260 rrdeng_readiness_wait((struct rrdengine_instance *)host->db[0].si);
261 }
262 }
263
264 if (!initialized) {
265 nd_log(
266 NDLS_DAEMON,
267 NDLP_CRIT,
268 "Host '%s': cannot initialize host with machine guid '%s'. Failed to initialize DB engine at '%s'.",
269 rrdhost_hostname(host),
270 host->machine_guid,
271 host->cache_dir);
272
273 rrd_wrlock();
274 rrdhost_free___while_having_rrd_wrlock(host);
275 rrd_wrunlock();
276 return NULL;
277 }
278 return host;
279 }
280 #endif
281
282 static void rrdhost_set_replication_parameters(RRDHOST *host, RRD_DB_MODE memory_mode, time_t period, time_t step) {
283 host->stream.replication.period = period;
284 host->stream.replication.step = step;
285 host->stream.rcv.status.replication.percent = 100.0;
286
287 switch(memory_mode) {
288 default:
289 case RRD_DB_MODE_ALLOC:
290 case RRD_DB_MODE_RAM:
291 if(host->stream.replication.period > (time_t) host->rrd_history_entries * (time_t) host->rrd_update_every)
292 host->stream.replication.period = (time_t) host->rrd_history_entries * (time_t) host->rrd_update_every;
293 break;
294
295 case RRD_DB_MODE_DBENGINE:
296 break;
297 }
298 }
299
300 RRDHOST *rrdhost_create(
301 const char *hostname,
302 const char *registry_hostname,
303 const char *guid,
304 const char *os,
305 const char *timezone,
306 const char *abbrev_timezone,
307 int32_t utc_offset,
308 const char *prog_name,
309 const char *prog_version,
310 int update_every,
311 long entries,
312 RRD_DB_MODE memory_mode,
313 bool health,
314 bool stream,
315 STRING *parents,
316 STRING *api_key,
317 STRING *send_charts_matching,
318 bool replication,
319 time_t replication_period,
320 time_t replication_step,
321 struct rrdhost_system_info *system_info,
322 int is_localhost,
323 bool archived
324 ) {
325 if(memory_mode == RRD_DB_MODE_DBENGINE && !dbengine_enabled) {
326 nd_log(NDLS_DAEMON, NDLP_ERR,
327 "memory mode 'dbengine' is not enabled, but host '%s' is configured for it. Falling back to 'alloc'",
328 hostname);
329
330 memory_mode = RRD_DB_MODE_ALLOC;
331 }
332
333 RRDHOST *host = callocz(1, sizeof(RRDHOST));
334 host->state_id = OBJECT_STATE_INIT_DEACTIVATED;
335
336 __atomic_add_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(RRDHOST), __ATOMIC_RELAXED);
337
338 strncpyz(host->machine_guid, guid, GUID_LEN + 1);
339 rrdhost_stream_path_init(host);
340 rrdhost_stream_parents_init(host);
341
342 set_host_properties(
343 host,
344 (update_every > 0) ? update_every : 1,
345 memory_mode,
346 registry_hostname,
347 os,
348 timezone,
349 abbrev_timezone,
350 utc_offset,
351 prog_name,
352 prog_version);
353
354 rrdhost_init_hostname(host, hostname);
355
356 host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries);
357 host->health.enabled = ((memory_mode == RRD_DB_MODE_NONE)) ? false : health;
358
359 spinlock_init(&host->receiver_lock);
360 spinlock_init(&host->rrdhost_update_lock);
361
362 if (likely(!archived)) {
363 rrd_functions_host_init(host);
364 host->stream.snd.status.last_connected = now_realtime_sec();
365 host->rrdlabels = rrdlabels_create();
366 stream_sender_structures_init(host, stream, parents, api_key, send_charts_matching);
367 }
368
369 if(replication)
370 rrdhost_option_set(host, RRDHOST_OPTION_REPLICATION);
371 else
372 rrdhost_option_clear(host, RRDHOST_OPTION_REPLICATION);
373
374 rrdhost_set_replication_parameters(host, memory_mode, replication_period, replication_step);
375
376 host->system_info = rrdhost_system_info_create();
377 rrdhost_system_info_swap(host->system_info, system_info);
378
379 rrdset_index_init(host);
380
381 if(is_localhost)
382 host->cache_dir = strdupz(netdata_configured_cache_dir);
383
384 // this is also needed for custom host variables - not only health
385 host->rrdvars = rrdvariables_create();
386
387 if (likely(!uuid_parse(host->machine_guid, host->host_id.uuid)))
388 sql_load_node_id(host);
389 else
390 error_report("Host machine GUID %s is not valid", host->machine_guid);
391
392 rrdcalc_rrdhost_index_init(host);
393
394 if (host->rrd_memory_mode == RRD_DB_MODE_DBENGINE) {
395 #ifdef ENABLE_DBENGINE
396 if (unittest_running) {
397 host = prepare_host_for_unittest(host);
398 if (!host)
399 return NULL;
400 }
401 else {
402 for(size_t tier = 0; tier < nd_profile.storage_tiers; tier++) {
403 host->db[tier].mode = RRD_DB_MODE_DBENGINE;
404 host->db[tier].eng = storage_engine_get(host->db[tier].mode);
405 host->db[tier].si = (STORAGE_INSTANCE *)multidb_ctx[tier];
406 host->db[tier].tier_grouping = get_tier_grouping(tier);
407 }
408 }
409 #else
410 fatal("RRD_DB_MODE_DBENGINE is not supported in this platform.");
411 #endif
412 }
413 else {
414 host->db[0].mode = host->rrd_memory_mode;
415 host->db[0].eng = storage_engine_get(host->db[0].mode);
416 host->db[0].si = NULL;
417 host->db[0].tier_grouping = get_tier_grouping(0);
418
419 #ifdef ENABLE_DBENGINE
420 // the first tier is reserved for the non-dbengine modes
421 for(size_t tier = 1; tier < nd_profile.storage_tiers; tier++) {
422 host->db[tier].mode = RRD_DB_MODE_DBENGINE;
423 host->db[tier].eng = storage_engine_get(host->db[tier].mode);
424 host->db[tier].si = (STORAGE_INSTANCE *) multidb_ctx[tier];
425 host->db[tier].tier_grouping = get_tier_grouping(tier);
426 }
427 #endif
428 }
429
430 // ------------------------------------------------------------------------
431 // init new ML host and update system_info to let upstreams know
432 // about ML functionality
433 //
434
435 if (is_localhost && host->system_info) {
436 rrdhost_system_info_ml_capable_set(host->system_info, ml_capable());
437 rrdhost_system_info_ml_enabled_set(host->system_info, ml_enabled(host));
438 rrdhost_system_info_mc_version_set(host->system_info, metric_correlations_version);
439 }
440
441 // ------------------------------------------------------------------------
442 // link it and add it to the index
443
444 rrd_wrlock();
445
446 RRDHOST *t = rrdhost_index_add_by_guid(host);
447 if(t != host) {
448 nd_log(NDLS_DAEMON, NDLP_NOTICE,
449 "Host '%s': cannot add host with machine guid '%s' to index. It already exists as host '%s' with machine guid '%s'.",
450 rrdhost_hostname(host), host->machine_guid, rrdhost_hostname(t), t->machine_guid);
451
452 if (!is_localhost)
453 rrdhost_free___while_having_rrd_wrlock(host);
454
455 rrd_wrunlock();
456 return NULL;
457 }
458
459 if(is_localhost)
460 DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(localhost, host, prev, next);
461 else
462 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(localhost, host, prev, next);
463
464 rrd_wrunlock();
465
466 // ------------------------------------------------------------------------
467
468 RRDHOST_TZ host_tz = rrdhost_tz_get(host);
469 nd_log(NDLS_DAEMON, NDLP_INFO,
470 "Host '%s' (at registry as '%s') with guid '%s' initialized"
471 ", os '%s'"
472 ", timezone '%s'"
473 ", program_name '%s'"
474 ", program_version '%s'"
475 ", update every %d"
476 ", memory mode %s"
477 ", history entries %d"
478 ", streaming %s"
479 " (to '%s' with api key '%s')"
480 ", health %s"
481 ", cache_dir '%s'"
482 ", alarms default handler '%s'"
483 ", alarms default recipient '%s'"
484 , rrdhost_hostname(host)
485 , rrdhost_registry_hostname(host)
486 , host->machine_guid
487 , rrdhost_os(host)
488 , host_tz.timezone
489 , rrdhost_program_name(host)
490 , rrdhost_program_version(host)
491 , host->rrd_update_every
492 , rrd_memory_mode_name(host->rrd_memory_mode)
493 , host->rrd_history_entries
494 ,
495 rrdhost_has_stream_sender_enabled(host)?"enabled":"disabled"
496 , string2str(host->stream.snd.destination)
497 , string2str(host->stream.snd.api_key)
498 , host->health.enabled ?"enabled":"disabled"
499 , host->cache_dir
500 , string2str(host->health.default_exec)
501 , string2str(host->health.default_recipient)
502 );
503 rrdhost_tz_free(&host_tz);
504
505 if(!archived) {
506 rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_INFO | RRDHOST_FLAG_METADATA_UPDATE);
507 if (is_localhost)
508 store_host_info_and_metadata(host);
509 rrdhost_load_rrdcontext_data(host);
510 ml_host_new(host);
511 } else
512 rrdhost_flag_set(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD | RRDHOST_FLAG_ARCHIVED | RRDHOST_FLAG_ORPHAN);
513
514 return host;
515 }
516
517 static void rrdhost_update(RRDHOST *host
518 , const char *hostname
519 , const char *registry_hostname
520 , const char *guid
521 , const char *os
522 , const char *timezone
523 , const char *abbrev_timezone
524 , int32_t utc_offset
525 , const char *prog_name
526 , const char *prog_version
527 , int update_every
528 , long history
529 , RRD_DB_MODE mode
530 , bool health
531 , bool stream
532 , STRING *parents
533 , STRING *api_key
534 , STRING *send_charts_matching
535 , bool replication
536 , time_t replication_period
537 , time_t replication_step
538 , struct rrdhost_system_info *system_info
539 )
540 {
541 UNUSED(guid);
542
543 // Streaming children may omit the User-Agent header, leaving prog_name/prog_version NULL.
544 // Match the defaults assigned on the host create path (for example in set_host_properties()/rrdhost_create())
545 // so the strcmp/string_strdupz calls below are safe.
546 if(!prog_name || !*prog_name) prog_name = "unknown";
547 if(!prog_version || !*prog_version) prog_version = "unknown";
548
549 spinlock_lock(&host->rrdhost_update_lock);
550
551 host->health.enabled = (mode == RRD_DB_MODE_NONE) ? 0 : health;
552
553 rrdhost_system_info_swap(host->system_info, system_info);
554 rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_INFO | RRDHOST_FLAG_METADATA_CLAIMID | RRDHOST_FLAG_METADATA_UPDATE);
555
556 rrdhost_init_os(host, os);
557 rrdhost_init_timezone(host, timezone, abbrev_timezone, utc_offset);
558
559 string_freez(host->registry_hostname);
560 host->registry_hostname = string_strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname);
561
562 if(strcmp(rrdhost_hostname(host), hostname) != 0) {
563 nd_log(NDLS_DAEMON, NDLP_WARNING,
564 "Host '%s' has been renamed to '%s'. If this is not intentional it may mean multiple hosts are using the same machine_guid.",
565 rrdhost_hostname(host), hostname);
566
567 rrdhost_init_hostname(host, hostname);
568 }
569
570 if(strcmp(rrdhost_program_name(host), prog_name) != 0) {
571 nd_log(NDLS_DAEMON, NDLP_NOTICE,
572 "Host '%s' switched program name from '%s' to '%s'",
573 rrdhost_hostname(host), rrdhost_program_name(host),
574 prog_name);
575
576 STRING *t = host->program_name;
577 host->program_name = string_strdupz(prog_name);
578 string_freez(t);
579 }
580
581 if(strcmp(rrdhost_program_version(host), prog_version) != 0) {
582 nd_log(NDLS_DAEMON, NDLP_NOTICE,
583 "Host '%s' switched program version from '%s' to '%s'",
584 rrdhost_hostname(host), rrdhost_program_version(host),
585 prog_version);
586
587 STRING *t = host->program_version;
588 host->program_version = string_strdupz(prog_version);
589 string_freez(t);
590 }
591
592 if(host->rrd_update_every != update_every)
593 nd_log(NDLS_DAEMON, NDLP_WARNING,
594 "Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds. "
595 "Restart netdata here to apply the new settings.",
596 rrdhost_hostname(host), host->rrd_update_every, update_every);
597
598 if(host->rrd_memory_mode != mode)
599 nd_log(NDLS_DAEMON, NDLP_WARNING,
600 "Host '%s' has memory mode '%s', but the wanted one is '%s'. "
601 "Restart netdata here to apply the new settings.",
602 rrdhost_hostname(host),
603 rrd_memory_mode_name(host->rrd_memory_mode),
604 rrd_memory_mode_name(mode));
605
606 else if(host->rrd_memory_mode != RRD_DB_MODE_DBENGINE && host->rrd_history_entries < history)
607 nd_log(NDLS_DAEMON, NDLP_WARNING,
608 "Host '%s' has history of %d entries, but the wanted one is %ld entries. "
609 "Restart netdata here to apply the new settings.",
610 rrdhost_hostname(host),
611 host->rrd_history_entries,
612 history);
613
614 if(!host->rrdvars)
615 host->rrdvars = rrdvariables_create();
616
617 host->stream.snd.status.last_connected = now_realtime_sec();
618
619 if (rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED)) {
620 rrdhost_flag_clear(host, RRDHOST_FLAG_ARCHIVED);
621
622 rrd_functions_host_init(host);
623
624 if(!host->rrdlabels)
625 host->rrdlabels = rrdlabels_create();
626
627 if (!host->rrdset_root_index)
628 rrdset_index_init(host);
629
630 stream_sender_structures_init(host, stream, parents, api_key, send_charts_matching);
631
632 rrdcalc_rrdhost_index_init(host);
633
634 if(replication)
635 rrdhost_option_set(host, RRDHOST_OPTION_REPLICATION);
636 else
637 rrdhost_option_clear(host, RRDHOST_OPTION_REPLICATION);
638
639 rrdhost_set_replication_parameters(host, host->rrd_memory_mode, replication_period, replication_step);
640
641 ml_host_new(host);
642
643 rrdhost_load_rrdcontext_data(host);
644 nd_log(NDLS_DAEMON, NDLP_DEBUG,
645 "Host %s is not in archived mode anymore",
646 rrdhost_hostname(host));
647 }
648
649 spinlock_unlock(&host->rrdhost_update_lock);
650 }
651
652 RRDHOST *rrdhost_find_or_create(
653 const char *hostname
654 , const char *registry_hostname
655 , const char *guid
656 , const char *os
657 , const char *timezone
658 , const char *abbrev_timezone
659 , int32_t utc_offset
660 , const char *prog_name
661 , const char *prog_version
662 , int update_every
663 , long history
664 ,
665 RRD_DB_MODE mode
666 , bool health
667 , bool stream
668 , STRING *parents
669 , STRING *api_key
670 , STRING *send_charts_matching
671 , bool replication
672 , time_t replication_period
673 , time_t replication_step
674 , struct rrdhost_system_info *system_info
675 , bool archived
676 ) {
677 RRDHOST *host = rrdhost_find_by_guid(guid);
678 if (unlikely(host && host->rrd_memory_mode != mode && rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))) {
679
680 if (likely(!archived && rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD)))
681 return host;
682
683 /* If a legacy memory mode instantiates all dbengine state must be discarded to avoid inconsistencies */
684 nd_log(NDLS_DAEMON, NDLP_INFO,
685 "Archived host '%s' has memory mode '%s', but the wanted one is '%s'. Discarding archived state.",
686 rrdhost_hostname(host),
687 rrd_memory_mode_name(host->rrd_memory_mode),
688 rrd_memory_mode_name(mode));
689
690 rrd_wrlock();
691 rrdhost_free___while_having_rrd_wrlock(host);
692 host = NULL;
693 rrd_wrunlock();
694 }
695
696 if(!host) {
697 host = rrdhost_create(
698 hostname
699 , registry_hostname
700 , guid
701 , os
702 , timezone
703 , abbrev_timezone
704 , utc_offset
705 , prog_name
706 , prog_version
707 , update_every
708 , history
709 , mode
710 , health
711 , stream
712 , parents
713 , api_key
714 , send_charts_matching
715 , replication
716 , replication_period
717 , replication_step
718 , system_info
719 , 0
720 , archived
721 );
722 }
723 else {
724 if (likely(!rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD)))
725 rrdhost_update(
726 host
727 , hostname
728 , registry_hostname
729 , guid
730 , os
731 , timezone
732 , abbrev_timezone
733 , utc_offset
734 , prog_name
735 , prog_version
736 , update_every
737 , history
738 , mode
739 , health
740 , stream
741 , parents
742 , api_key
743 , send_charts_matching
744 , replication
745 , replication_period
746 , replication_step
747 , system_info);
748 }
749
750 return host;
751 }
752
753 bool rrdhost_should_be_cleaned_up(RRDHOST *host, RRDHOST *protected_host, time_t now_s) {
754 if(host != protected_host
755 && host != localhost
756 && rrdhost_receiver_replicating_charts(host) == 0
757 && rrdhost_sender_replicating_charts(host) == 0
758 && rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)
759 && !rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD | RRDHOST_FLAG_COLLECTOR_ONLINE)
760 && health_evloop_current_iteration() - rrdhost_health_evloop_last_iteration(host) > 10
761 && host->stream.rcv.status.last_disconnected
762 && host->stream.rcv.status.last_disconnected + rrdhost_cleanup_orphan_to_archive_time_s < now_s)
763 return true;
764
765 return false;
766 }
767
768 bool rrdhost_should_run_health(RRDHOST *host) {
769 if (!host->health.enabled || !rrdhost_flag_check(host, RRDHOST_FLAG_COLLECTOR_ONLINE) ||
770 rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN) || rrdhost_ingestion_status(host) != RRDHOST_INGEST_STATUS_ONLINE)
771 return false;
772
773 return true;
774 }
775
776 // ----------------------------------------------------------------------------
777 // RRDHOST - free
778
779 void rrdhost_cleanup_data_collection_and_health(RRDHOST *host) {
780 stream_receiver_signal_to_stop_and_wait(host, STREAM_HANDSHAKE_SND_DISCONNECT_HOST_CLEANUP);
781
782 rrdhost_pluginsd_send_chart_slots_free(host);
783 rrdhost_pluginsd_receive_chart_slots_free(host);
784
785 rrdcalc_delete_all(host);
786 rrdset_index_destroy(host);
787 rrdcalc_rrdhost_index_destroy(host);
788 health_alarm_log_free(host);
789
790 ml_host_delete(host);
791
792 freez(host->exporting_flags);
793 host->exporting_flags = NULL;
794
795 rrd_functions_host_destroy(host);
796 rrdvariables_destroy(host->rrdvars);
797 host->rrdvars = NULL;
798
799 rrdhost_stream_path_clear(host, true);
800 stream_sender_structures_free(host);
801
802 rrdhost_flag_set(host, RRDHOST_FLAG_ARCHIVED | RRDHOST_FLAG_ORPHAN);
803
804 nd_log(NDLS_DAEMON, NDLP_DEBUG,
805 "RRD: 'host:%s' is now in archive mode...",
806 rrdhost_hostname(host));
807 }
808
809 static void rrdhost_unlink___while_having_rrd_wrlock(RRDHOST *host) {
810 // Remove it from the indexes first, so blocking teardown cannot rediscover it.
811 rrdhost_index_del_by_guid(host);
812
813 if (host->prev)
814 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(localhost, host, prev, next);
815 }
816
817 static void rrdhost_free_unlinked(RRDHOST *host) {
818 rrdhost_cleanup_data_collection_and_health(host);
819
820 // ------------------------------------------------------------------------
821 // free it
822
823 pulse_host_status(host, PULSE_HOST_STATUS_DELETED, 0);
824 __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(RRDHOST), __ATOMIC_RELAXED);
825
826 freez(host->cache_dir);
827 simple_pattern_free(host->stream.snd.charts_matching);
828 rrdhost_system_info_free(host->system_info);
829
830 rrdhost_destroy_rrdcontexts(host);
831 rrdlabels_destroy(host->rrdlabels);
832 destroy_aclk_config(host);
833
834 string_freez(host->hostname);
835 string_freez(host->os);
836 string_freez(host->timezone);
837 string_freez(host->abbrev_timezone);
838 string_freez(host->program_name);
839 string_freez(host->program_version);
840 string_freez(host->health.default_exec);
841 string_freez(host->health.default_recipient);
842 string_freez(host->registry_hostname);
843 string_freez(host->stream.snd.api_key);
844 string_freez(host->stream.snd.destination);
845 freez(host);
846 }
847
848 void rrdhost_free___while_having_rrd_wrlock(RRDHOST *host) {
849 if(!host) return;
850
851 rrdhost_unlink___while_having_rrd_wrlock(host);
852 rrdhost_free_unlinked(host);
853 }
854
855 void rrdhost_free___without_having_rrd_wrlock(RRDHOST *host) {
856 if(!host) return;
857
858 rrd_wrlock();
859 rrdhost_unlink___while_having_rrd_wrlock(host);
860 rrd_wrunlock();
861
862 rrdhost_free_unlinked(host);
863 }
864
865 void rrdhost_free_all(void) {
866 rrd_wrlock();
867
868 /* Make sure child-hosts are released before the localhost. */
869 while(localhost && localhost->next)
870 rrdhost_free___while_having_rrd_wrlock(localhost->next);
871
872 if(localhost)
873 rrdhost_free___while_having_rrd_wrlock(localhost);
874
875 localhost = NULL;
876
877 RRDHOST *host;
878 dfe_start_write(rrdhost_root_index, host) {
879 fprintf(stderr, "RRDHOST: MACHINE_GUID '%s' is still in the dictionary!\n",
880 host_dfe.name);
881 }
882 dfe_done(host);
883
884 dictionary_garbage_collect(rrdhost_root_index);
885 dictionary_destroy(rrdhost_root_index);
886 rrdhost_root_index = NULL;
887
888 rrd_wrunlock();
889 }