]> arthur.barton.de Git - netdata.git/blob - src/rrdhost.c
each host can have its own settings for history, update_every, rrd memory mode, healt...
[netdata.git] / src / rrdhost.c
1 #define NETDATA_RRD_INTERNALS 1
2 #include "common.h"
3
4 RRDHOST *localhost = NULL;
5
6 // ----------------------------------------------------------------------------
7 // RRDHOST index
8
9 int rrdhost_compare(void* a, void* b) {
10     if(((RRDHOST *)a)->hash_machine_guid < ((RRDHOST *)b)->hash_machine_guid) return -1;
11     else if(((RRDHOST *)a)->hash_machine_guid > ((RRDHOST *)b)->hash_machine_guid) return 1;
12     else return strcmp(((RRDHOST *)a)->machine_guid, ((RRDHOST *)b)->machine_guid);
13 }
14
15 avl_tree_lock rrdhost_root_index = {
16         .avl_tree = { NULL, rrdhost_compare },
17         .rwlock = AVL_LOCK_INITIALIZER
18 };
19
20 RRDHOST *rrdhost_find(const char *guid, uint32_t hash) {
21     debug(D_RRDHOST, "Searching in index for host with guid '%s'", guid);
22
23     RRDHOST tmp;
24     strncpyz(tmp.machine_guid, guid, GUID_LEN);
25     tmp.hash_machine_guid = (hash)?hash:simple_hash(tmp.machine_guid);
26
27     return (RRDHOST *)avl_search_lock(&(rrdhost_root_index), (avl *) &tmp);
28 }
29
30 #define rrdhost_index_add(rrdhost) (RRDHOST *)avl_insert_lock(&(rrdhost_root_index), (avl *)(rrdhost))
31 #define rrdhost_index_del(rrdhost) (RRDHOST *)avl_remove_lock(&(rrdhost_root_index), (avl *)(rrdhost))
32
33
34 // ----------------------------------------------------------------------------
35 // RRDHOST - internal helpers
36
37 static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) {
38     freez(host->hostname);
39     host->hostname = strdupz(hostname);
40     host->hash_hostname = simple_hash(host->hostname);
41 }
42
43 static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) {
44     strncpy(host->machine_guid, machine_guid, GUID_LEN);
45     host->machine_guid[GUID_LEN] = '\0';
46     host->hash_machine_guid = simple_hash(host->machine_guid);
47 }
48
49 // ----------------------------------------------------------------------------
50 // RRDHOST - add a host
51
52 RRDHOST *rrdhost_create(const char *hostname, const char *guid) {
53     debug(D_RRDHOST, "Adding host '%s' with guid '%s'", hostname, guid);
54
55     RRDHOST *host = callocz(1, sizeof(RRDHOST));
56
57     host->rrd_update_every    = default_localhost_rrd_update_every;
58     host->rrd_history_entries = default_localhost_rrd_history_entries;
59     host->rrd_memory_mode     = default_localhost_rrd_memory_mode;
60     host->health_enabled      = default_localhost_health_enabled;
61
62     pthread_rwlock_init(&(host->rrdset_root_rwlock), NULL);
63
64     rrdhost_init_hostname(host, hostname);
65     rrdhost_init_machine_guid(host, guid);
66
67     avl_init_lock(&(host->rrdset_root_index), rrdset_compare);
68     avl_init_lock(&(host->rrdset_root_index_name), rrdset_compare_name);
69     avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare);
70     avl_init_lock(&(host->variables_root_index), rrdvar_compare);
71
72
73     // ------------------------------------------------------------------------
74     // initialize health variables
75
76     host->health_log.next_log_id = 1;
77     host->health_log.next_alarm_id = 1;
78     host->health_log.max = 1000;
79     host->health_log.next_log_id =
80     host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
81
82     long n = config_get_number("health", "in memory max health log entries", host->health_log.max);
83     if(n < 10) {
84         error("Health configuration has invalid max log entries %ld. Using default %u", n, host->health_log.max);
85         config_set_number("health", "in memory max health log entries", (long)host->health_log.max);
86     }
87     else
88         host->health_log.max = (unsigned int)n;
89
90     pthread_rwlock_init(&(host->health_log.alarm_log_rwlock), NULL);
91
92     char filename[FILENAME_MAX + 1];
93
94     if(!localhost) {
95         // this is localhost
96         snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", netdata_configured_varlib_dir);
97         host->health_log_filename = strdupz(config_get("health", "health db file", filename));
98     }
99     else {
100         // this is not localhost - append our GUID to localhost path
101         snprintfz(filename, FILENAME_MAX, "%s.%s", localhost->health_log_filename, host->machine_guid);
102         host->health_log_filename = strdupz(filename);
103     }
104
105     snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_plugins_dir);
106     host->health_default_exec = strdupz(config_get("health", "script to execute on alarm", filename));
107     host->health_default_recipient = strdup("root");
108
109
110     // ------------------------------------------------------------------------
111     // load health configuration
112
113     health_alarm_log_load(host);
114     health_alarm_log_open(host);
115
116     rrdhost_rwlock(host);
117     health_readdir(host, health_config_dir());
118     rrdhost_unlock(host);
119
120
121     // ------------------------------------------------------------------------
122     // add it to the index
123
124     if(rrdhost_index_add(host) != host)
125         fatal("Cannot add host '%s' to index. It already exists.", hostname);
126
127     debug(D_RRDHOST, "Added host '%s' with guid '%s'", host->hostname, host->machine_guid);
128     return host;
129 }
130
131 RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid) {
132     debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
133
134     RRDHOST *host = rrdhost_find(guid, 0);
135     if(!host)
136         host = rrdhost_create(hostname, guid);
137
138     return host;
139 }
140
141 // ----------------------------------------------------------------------------
142 // RRDHOST global / startup initialization
143
144 void rrd_init(char *hostname) {
145     debug(D_RRDHOST, "Initializing localhost with hostname '%s'", hostname);
146     localhost = rrdhost_create(hostname, registry_get_this_machine_guid());
147 }
148
149 // ----------------------------------------------------------------------------
150 // RRDHOST - locks
151
152 void rrdhost_rwlock(RRDHOST *host) {
153     debug(D_RRDHOST, "Write lock host '%s'", host->hostname);
154     pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
155 }
156
157 void rrdhost_rdlock(RRDHOST *host) {
158     debug(D_RRDHOST, "Read lock host '%s'", host->hostname);
159     pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
160 }
161
162 void rrdhost_unlock(RRDHOST *host) {
163     debug(D_RRDHOST, "Unlock host '%s'", host->hostname);
164     pthread_rwlock_unlock(&host->rrdset_root_rwlock);
165 }
166
167 void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
168     debug(D_RRDHOST, "Read lock host '%s'", host->hostname);
169
170     int ret = pthread_rwlock_trywrlock(&host->rrdset_root_rwlock);
171     if(ret == 0)
172         fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
173 }
174
175 void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
176     debug(D_RRDHOST, "Write lock host '%s'", host->hostname);
177
178     int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
179     if(ret == 0)
180         fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
181 }
182
183 void rrdhost_free(RRDHOST *host) {
184     if(!host) return;
185
186     info("Freeing all memory for host '%s'...", host->hostname);
187
188     rrdhost_rwlock(host);
189
190     RRDSET *st;
191     for(st = host->rrdset_root; st ;) {
192         RRDSET *next = st->next;
193
194         pthread_rwlock_wrlock(&st->rwlock);
195
196         while(st->variables)  rrdsetvar_free(st->variables);
197         while(st->alarms)     rrdsetcalc_unlink(st->alarms);
198         while(st->dimensions) rrddim_free(st, st->dimensions);
199
200         if(unlikely(rrdset_index_del(host, st) != st))
201             error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
202
203         rrdset_index_del_name(host, st);
204
205         st->rrdfamily->use_count--;
206         if(!st->rrdfamily->use_count)
207             rrdfamily_free(host, st->rrdfamily);
208
209         pthread_rwlock_unlock(&st->rwlock);
210
211         if(st->mapped == RRD_MEMORY_MODE_SAVE || st->mapped == RRD_MEMORY_MODE_MAP) {
212             debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
213             munmap(st, st->memsize);
214         }
215         else
216             freez(st);
217
218         st = next;
219     }
220     host->rrdset_root = NULL;
221
222     freez(host->health_default_exec);
223     freez(host->health_default_recipient);
224     freez(host->health_log_filename);
225     freez(host->hostname);
226     rrdhost_unlock(host);
227     freez(host);
228
229     info("Host memory cleanup completed...");
230 }
231
232 void rrdhost_save(RRDHOST *host) {
233     if(!host) return;
234
235     info("Saving host '%s' database...", host->hostname);
236
237     RRDSET *st;
238     RRDDIM *rd;
239
240     // we get an write lock
241     // to ensure only one thread is saving the database
242     rrdhost_rwlock(host);
243
244     for(st = host->rrdset_root; st ; st = st->next) {
245         pthread_rwlock_rdlock(&st->rwlock);
246
247         if(st->mapped == RRD_MEMORY_MODE_SAVE) {
248             debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
249             savememory(st->cache_filename, st, st->memsize);
250         }
251
252         for(rd = st->dimensions; rd ; rd = rd->next) {
253             if(likely(rd->memory_mode == RRD_MEMORY_MODE_SAVE)) {
254                 debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
255                 savememory(rd->cache_filename, rd, rd->memsize);
256             }
257         }
258
259         pthread_rwlock_unlock(&st->rwlock);
260     }
261
262     rrdhost_unlock(host);
263 }
264
265 void rrdhost_free_all(void) {
266     RRDHOST *host = localhost;
267
268     // FIXME: lock all hosts
269
270     while(host) {
271         RRDHOST *next = host = host->next;
272         rrdhost_free(host);
273         host = next;
274     }
275
276     localhost = NULL;
277
278     // FIXME: unlock all hosts
279 }
280
281 void rrdhost_save_all(void) {
282     RRDHOST *host;
283     for(host = localhost; host ; host = host->next)
284         rrdhost_save(host);
285 }