]> arthur.barton.de Git - netdata.git/blob - src/rrdhost.c
hosts except localhost save files in subdirectory in /var/cache/netdata and /var...
[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
97         host->cache_dir = strdupz(netdata_configured_cache_dir);
98         host->varlib_dir = strdupz(netdata_configured_varlib_dir);
99
100         snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", host->varlib_dir);
101         host->health_log_filename = strdupz(config_get("health", "health db file", filename));
102
103     }
104     else {
105         // this is not localhost - append our GUID to localhost path
106
107         snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_cache_dir, host->machine_guid);
108         host->cache_dir = strdupz(filename);
109
110         if(host->rrd_memory_mode == RRD_MEMORY_MODE_MAP || host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
111             int r = mkdir(host->cache_dir, 0775);
112             if(r != 0 && errno != EEXIST)
113                 error("Cannot create directory '%s'", host->cache_dir);
114         }
115
116         snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_varlib_dir, host->machine_guid);
117         host->varlib_dir = strdupz(filename);
118
119         if(host->health_enabled) {
120             int r = mkdir(host->varlib_dir, 0775);
121             if(r != 0 && errno != EEXIST)
122                 error("Cannot create directory '%s'", host->varlib_dir);
123         }
124
125         snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", host->varlib_dir);
126         host->health_log_filename = strdupz(filename);
127
128     }
129
130     snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_plugins_dir);
131     host->health_default_exec = strdupz(config_get("health", "script to execute on alarm", filename));
132     host->health_default_recipient = strdup("root");
133
134
135     // ------------------------------------------------------------------------
136     // load health configuration
137
138     health_alarm_log_load(host);
139     health_alarm_log_open(host);
140
141     rrdhost_rwlock(host);
142     health_readdir(host, health_config_dir());
143     rrdhost_unlock(host);
144
145
146     // ------------------------------------------------------------------------
147     // add it to the index
148
149     if(rrdhost_index_add(host) != host)
150         fatal("Cannot add host '%s' to index. It already exists.", hostname);
151
152     debug(D_RRDHOST, "Added host '%s' with guid '%s'", host->hostname, host->machine_guid);
153     return host;
154 }
155
156 RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid) {
157     debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
158
159     RRDHOST *host = rrdhost_find(guid, 0);
160     if(!host)
161         host = rrdhost_create(hostname, guid);
162
163     return host;
164 }
165
166 // ----------------------------------------------------------------------------
167 // RRDHOST global / startup initialization
168
169 void rrd_init(char *hostname) {
170     debug(D_RRDHOST, "Initializing localhost with hostname '%s'", hostname);
171     localhost = rrdhost_create(hostname, registry_get_this_machine_guid());
172 }
173
174 // ----------------------------------------------------------------------------
175 // RRDHOST - locks
176
177 void rrdhost_rwlock(RRDHOST *host) {
178     debug(D_RRDHOST, "Write lock host '%s'", host->hostname);
179     pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
180 }
181
182 void rrdhost_rdlock(RRDHOST *host) {
183     debug(D_RRDHOST, "Read lock host '%s'", host->hostname);
184     pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
185 }
186
187 void rrdhost_unlock(RRDHOST *host) {
188     debug(D_RRDHOST, "Unlock host '%s'", host->hostname);
189     pthread_rwlock_unlock(&host->rrdset_root_rwlock);
190 }
191
192 void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
193     debug(D_RRDHOST, "Read lock host '%s'", host->hostname);
194
195     int ret = pthread_rwlock_trywrlock(&host->rrdset_root_rwlock);
196     if(ret == 0)
197         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);
198 }
199
200 void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
201     debug(D_RRDHOST, "Write lock host '%s'", host->hostname);
202
203     int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
204     if(ret == 0)
205         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);
206 }
207
208 void rrdhost_free(RRDHOST *host) {
209     if(!host) return;
210
211     info("Freeing all memory for host '%s'...", host->hostname);
212
213     rrdhost_rwlock(host);
214
215     RRDSET *st;
216     for(st = host->rrdset_root; st ;) {
217         RRDSET *next = st->next;
218
219         rrdset_free(st);
220
221         st = next;
222     }
223     host->rrdset_root = NULL;
224
225     freez(host->cache_dir);
226     freez(host->varlib_dir);
227     freez(host->health_default_exec);
228     freez(host->health_default_recipient);
229     freez(host->health_log_filename);
230     freez(host->hostname);
231     rrdhost_unlock(host);
232     freez(host);
233
234     info("Host memory cleanup completed...");
235 }
236
237 void rrdhost_save(RRDHOST *host) {
238     if(!host) return;
239
240     info("Saving host '%s' database...", host->hostname);
241
242     RRDSET *st;
243     RRDDIM *rd;
244
245     // we get a write lock
246     // to ensure only one thread is saving the database
247     rrdhost_rwlock(host);
248
249     for(st = host->rrdset_root; st ; st = st->next) {
250         pthread_rwlock_rdlock(&st->rwlock);
251
252         if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
253             debug(D_RRD_STATS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
254             savememory(st->cache_filename, st, st->memsize);
255         }
256
257         for(rd = st->dimensions; rd ; rd = rd->next) {
258             if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
259                 debug(D_RRD_STATS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
260                 savememory(rd->cache_filename, rd, rd->memsize);
261             }
262         }
263
264         pthread_rwlock_unlock(&st->rwlock);
265     }
266
267     rrdhost_unlock(host);
268 }
269
270 void rrdhost_free_all(void) {
271     RRDHOST *host = localhost;
272
273     // FIXME: lock all hosts
274
275     while(host) {
276         RRDHOST *next = host = host->next;
277         rrdhost_free(host);
278         host = next;
279     }
280
281     localhost = NULL;
282
283     // FIXME: unlock all hosts
284 }
285
286 void rrdhost_save_all(void) {
287     info("Saving database...");
288
289     RRDHOST *host;
290     for(host = localhost; host ; host = host->next)
291         rrdhost_save(host);
292 }