1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 
22 #include "cfg.h"
23 #include "pid.h"
24 #include "db.h"
25 #include "log.h"
26 #include "dbcache.h"
27 #include "zbxserver.h"
28 #include "daemon.h"
29 #include "zbxself.h"
30 #include "db.h"
31 
32 #include "timer.h"
33 
34 #define ZBX_TIMER_DELAY		SEC_PER_MIN
35 
36 extern unsigned char	process_type, program_type;
37 extern int		server_num, process_num;
38 extern int		CONFIG_TIMER_FORKS;
39 
40 /* trigger -> functions cache */
41 typedef struct
42 {
43 	zbx_uint64_t		triggerid;
44 	zbx_vector_uint64_t	functionids;
45 }
46 zbx_trigger_functions_t;
47 
48 /* addition data for event maintenance calculations to pair with zbx_event_suppress_query_t */
49 typedef struct
50 {
51 	zbx_uint64_t			eventid;
52 	zbx_vector_uint64_pair_t	maintenances;
53 }
54 zbx_event_suppress_data_t;
55 
56 /******************************************************************************
57  *                                                                            *
58  * Function: log_host_maintenance_update                                      *
59  *                                                                            *
60  * Purpose: log host maintenance changes                                      *
61  *                                                                            *
62  ******************************************************************************/
log_host_maintenance_update(const zbx_host_maintenance_diff_t * diff)63 static void	log_host_maintenance_update(const zbx_host_maintenance_diff_t* diff)
64 {
65 	char	*msg = NULL;
66 	size_t	msg_alloc = 0, msg_offset = 0;
67 	int	maintenance_off = 0;
68 
69 	if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS))
70 	{
71 		if (HOST_MAINTENANCE_STATUS_ON == diff->maintenance_status)
72 		{
73 			zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "putting host (" ZBX_FS_UI64 ") into",
74 					diff->hostid);
75 		}
76 		else
77 		{
78 			maintenance_off = 1;
79 			zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "taking host (" ZBX_FS_UI64 ") out of",
80 				diff->hostid);
81 		}
82 	}
83 	else
84 		zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "changing host (" ZBX_FS_UI64 ")", diff->hostid);
85 
86 	zbx_strcpy_alloc(&msg, &msg_alloc, &msg_offset, " maintenance");
87 
88 	if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID) && 0 != diff->maintenanceid)
89 		zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "(" ZBX_FS_UI64 ")", diff->maintenanceid);
90 
91 
92 	if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE) && 0 == maintenance_off)
93 	{
94 		const char	*description[] = {"with data collection", "without data collection"};
95 
96 		zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, " %s", description[diff->maintenance_type]);
97 	}
98 
99 	zabbix_log(LOG_LEVEL_DEBUG, "%s", msg);
100 	zbx_free(msg);
101 }
102 
103 /******************************************************************************
104  *                                                                            *
105  * Function: db_update_host_maintenances                                      *
106  *                                                                            *
107  * Purpose: update host maintenance properties in database                    *
108  *                                                                            *
109  ******************************************************************************/
db_update_host_maintenances(const zbx_vector_ptr_t * updates)110 static void	db_update_host_maintenances(const zbx_vector_ptr_t *updates)
111 {
112 	int					i;
113 	const zbx_host_maintenance_diff_t	*diff;
114 	char					*sql = NULL;
115 	size_t					sql_alloc = 0, sql_offset = 0;
116 
117 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
118 
119 	for (i = 0; i < updates->values_num; i++)
120 	{
121 		char	delim = ' ';
122 
123 		diff = (const zbx_host_maintenance_diff_t *)updates->values[i];
124 
125 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hosts set");
126 
127 		if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID))
128 		{
129 			if (0 != diff->maintenanceid)
130 			{
131 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenanceid=" ZBX_FS_UI64, delim,
132 						diff->maintenanceid);
133 			}
134 			else
135 			{
136 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenanceid=null", delim);
137 			}
138 
139 			delim = ',';
140 		}
141 
142 		if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE))
143 		{
144 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_type=%u", delim,
145 					diff->maintenance_type);
146 			delim = ',';
147 		}
148 
149 		if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS))
150 		{
151 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_status=%u", delim,
152 					diff->maintenance_status);
153 			delim = ',';
154 		}
155 
156 		if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM))
157 		{
158 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_from=%d", delim,
159 					diff->maintenance_from);
160 		}
161 
162 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where hostid=" ZBX_FS_UI64 ";\n", diff->hostid);
163 
164 		if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
165 			break;
166 
167 		if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
168 			log_host_maintenance_update(diff);
169 	}
170 
171 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
172 
173 	if (16 < sql_offset)
174 		DBexecute("%s", sql);
175 
176 	zbx_free(sql);
177 }
178 
179 /******************************************************************************
180  *                                                                            *
181  * Function: db_remove_expired_event_suppress_data                            *
182  *                                                                            *
183  * Purpose: remove expired event_suppress records                             *
184  *                                                                            *
185  ******************************************************************************/
db_remove_expired_event_suppress_data(int now)186 static void	db_remove_expired_event_suppress_data(int now)
187 {
188 	DBbegin();
189 	DBexecute("delete from event_suppress where suppress_until<%d", now);
190 	DBcommit();
191 }
192 
193 /******************************************************************************
194  *                                                                            *
195  * Function: event_suppress_data_free                                         *
196  *                                                                            *
197  * Purpose: free event suppress data structure                                *
198  *                                                                            *
199  ******************************************************************************/
event_suppress_data_free(zbx_event_suppress_data_t * data)200 static void	event_suppress_data_free(zbx_event_suppress_data_t *data)
201 {
202 	zbx_vector_uint64_pair_destroy(&data->maintenances);
203 	zbx_free(data);
204 }
205 
206 /******************************************************************************
207  *                                                                            *
208  * Function: event_queries_fetch                                              *
209  *                                                                            *
210  * Purpose: fetch events that need to be queried for maintenance              *
211  *                                                                            *
212  ******************************************************************************/
event_queries_fetch(DB_RESULT result,zbx_vector_ptr_t * event_queries)213 static void	event_queries_fetch(DB_RESULT result, zbx_vector_ptr_t *event_queries)
214 {
215 	DB_ROW				row;
216 	zbx_uint64_t			eventid;
217 	zbx_event_suppress_query_t	*query = NULL;
218 
219 	while (NULL != (row = DBfetch(result)))
220 	{
221 		ZBX_STR2UINT64(eventid, row[0]);
222 
223 		if (NULL == query || eventid != query->eventid)
224 		{
225 			query = (zbx_event_suppress_query_t *)zbx_malloc(NULL, sizeof(zbx_event_suppress_query_t));
226 
227 			query->eventid = eventid;
228 			ZBX_STR2UINT64(query->triggerid, row[1]);
229 			ZBX_DBROW2UINT64(query->r_eventid, row[2]);
230 			zbx_vector_uint64_create(&query->functionids);
231 			zbx_vector_ptr_create(&query->tags);
232 			zbx_vector_uint64_pair_create(&query->maintenances);
233 			zbx_vector_ptr_append(event_queries, query);
234 		}
235 
236 		if (FAIL == DBis_null(row[3]))
237 		{
238 			zbx_tag_t	*tag;
239 
240 			tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t));
241 			tag->tag = zbx_strdup(NULL, row[3]);
242 			tag->value = zbx_strdup(NULL, row[4]);
243 			zbx_vector_ptr_append(&query->tags, tag);
244 
245 		}
246 	}
247 }
248 
249 /******************************************************************************
250  *                                                                            *
251  * Function: db_get_query_events                                              *
252  *                                                                            *
253  * Purpose: get open, recently resolved and resolved problems with suppress   *
254  *          data from database and prepare event query, event data structures *
255  *                                                                            *
256  ******************************************************************************/
db_get_query_events(zbx_vector_ptr_t * event_queries,zbx_vector_ptr_t * event_data)257 static void	db_get_query_events(zbx_vector_ptr_t *event_queries, zbx_vector_ptr_t *event_data)
258 {
259 	DB_ROW				row;
260 	DB_RESULT			result;
261 	zbx_event_suppress_data_t	*data = NULL;
262 	zbx_uint64_t			eventid;
263 	zbx_uint64_pair_t		pair;
264 	zbx_vector_uint64_t		eventids;
265 
266 	/* get open or recently closed problems */
267 
268 	result = DBselect("select p.eventid,p.objectid,p.r_eventid,t.tag,t.value"
269 			" from problem p"
270 			" left join problem_tag t"
271 				" on p.eventid=t.eventid"
272 			" where p.source=%d"
273 				" and p.object=%d"
274 				" and " ZBX_SQL_MOD(p.eventid, %d) "=%d"
275 			" order by p.eventid",
276 			EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER, CONFIG_TIMER_FORKS, process_num - 1);
277 
278 	event_queries_fetch(result, event_queries);
279 	DBfree_result(result);
280 
281 	/* get event suppress data */
282 
283 	zbx_vector_uint64_create(&eventids);
284 
285 	result = DBselect("select eventid,maintenanceid,suppress_until"
286 			" from event_suppress"
287 			" where " ZBX_SQL_MOD(eventid, %d) "=%d"
288 			" order by eventid",
289 			CONFIG_TIMER_FORKS, process_num - 1);
290 
291 	while (NULL != (row = DBfetch(result)))
292 	{
293 		ZBX_STR2UINT64(eventid, row[0]);
294 
295 		if (FAIL == zbx_vector_ptr_bsearch(event_queries, &eventid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))
296 			zbx_vector_uint64_append(&eventids, eventid);
297 
298 		if (NULL == data || data->eventid != eventid)
299 		{
300 			data = (zbx_event_suppress_data_t *)zbx_malloc(NULL, sizeof(zbx_event_suppress_data_t));
301 			data->eventid = eventid;
302 			zbx_vector_uint64_pair_create(&data->maintenances);
303 			zbx_vector_ptr_append(event_data, data);
304 		}
305 
306 		ZBX_DBROW2UINT64(pair.first, row[1]);
307 		pair.second = atoi(row[2]);
308 		zbx_vector_uint64_pair_append(&data->maintenances, pair);
309 	}
310 	DBfree_result(result);
311 
312 	/* get missing event data */
313 
314 	if (0 != eventids.values_num)
315 	{
316 		char	*sql = NULL;
317 		size_t	sql_alloc = 0, sql_offset = 0;
318 
319 		zbx_vector_uint64_uniq(&eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
320 
321 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
322 				"select e.eventid,e.objectid,er.r_eventid,t.tag,t.value"
323 				" from events e"
324 				" left join event_recovery er"
325 					" on e.eventid=er.eventid"
326 				" left join problem_tag t"
327 					" on e.eventid=t.eventid"
328 				" where");
329 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "e.eventid", eventids.values, eventids.values_num);
330 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by e.eventid");
331 
332 		result = DBselect("%s", sql);
333 		zbx_free(sql);
334 
335 		event_queries_fetch(result, event_queries);
336 		DBfree_result(result);
337 
338 		zbx_vector_ptr_sort(event_queries, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
339 	}
340 
341 	zbx_vector_uint64_destroy(&eventids);
342 }
343 
344 /******************************************************************************
345  *                                                                            *
346  * Function: db_get_query_functions                                           *
347  *                                                                            *
348  * Purpose: get event query functionids from database                         *
349  *                                                                            *
350  ******************************************************************************/
db_get_query_functions(zbx_vector_ptr_t * event_queries)351 static void	db_get_query_functions(zbx_vector_ptr_t *event_queries)
352 {
353 	DB_ROW				row;
354 	DB_RESULT			result;
355 	int				i;
356 	zbx_vector_uint64_t		triggerids;
357 	zbx_hashset_t			triggers;
358 	zbx_hashset_iter_t		iter;
359 	char				*sql = NULL;
360 	size_t				sql_alloc = 0, sql_offset = 0;
361 	zbx_trigger_functions_t		*trigger = NULL, trigger_local;
362 	zbx_uint64_t			triggerid, functionid;
363 	zbx_event_suppress_query_t	*query;
364 
365 	/* cache functionids by triggerids */
366 
367 	zbx_hashset_create(&triggers, 100, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
368 
369 	zbx_vector_uint64_create(&triggerids);
370 
371 	for (i = 0; i < event_queries->values_num; i++)
372 	{
373 		query = (zbx_event_suppress_query_t *)event_queries->values[i];
374 		zbx_vector_uint64_append(&triggerids, query->triggerid);
375 	}
376 
377 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
378 	zbx_vector_uint64_uniq(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
379 
380 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select functionid,triggerid from functions where");
381 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids.values,
382 			triggerids.values_num);
383 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by triggerid");
384 
385 	result = DBselect("%s", sql);
386 	zbx_free(sql);
387 
388 	while (NULL != (row = DBfetch(result)))
389 	{
390 		ZBX_STR2UINT64(functionid, row[0]);
391 		ZBX_STR2UINT64(triggerid, row[1]);
392 
393 		if (NULL == trigger || trigger->triggerid != triggerid)
394 		{
395 			trigger_local.triggerid = triggerid;
396 			trigger = (zbx_trigger_functions_t *)zbx_hashset_insert(&triggers, &trigger_local,
397 					sizeof(trigger_local));
398 			zbx_vector_uint64_create(&trigger->functionids);
399 		}
400 		zbx_vector_uint64_append(&trigger->functionids, functionid);
401 	}
402 	DBfree_result(result);
403 
404 	/*  copy functionids to event queries */
405 
406 	for (i = 0; i < event_queries->values_num; i++)
407 	{
408 		query = (zbx_event_suppress_query_t *)event_queries->values[i];
409 
410 		if (NULL == (trigger = (zbx_trigger_functions_t *)zbx_hashset_search(&triggers, &query->triggerid)))
411 			continue;
412 
413 		zbx_vector_uint64_append_array(&query->functionids, trigger->functionids.values,
414 				trigger->functionids.values_num);
415 	}
416 
417 	zbx_hashset_iter_reset(&triggers, &iter);
418 	while (NULL != (trigger = (zbx_trigger_functions_t *)zbx_hashset_iter_next(&iter)))
419 		zbx_vector_uint64_destroy(&trigger->functionids);
420 	zbx_hashset_destroy(&triggers);
421 
422 	zbx_vector_uint64_destroy(&triggerids);
423 }
424 
425 /******************************************************************************
426  *                                                                            *
427  * Function: db_update_event_suppress_data                                    *
428  *                                                                            *
429  * Purpose: create/update event suppress data to reflect latest maintenance   *
430  *          changes in cache                                                  *
431  *                                                                            *
432  * Parameters: suppressed_num - [OUT] the number of suppressed events         *
433  *                                                                            *
434  ******************************************************************************/
db_update_event_suppress_data(int * suppressed_num)435 static void	db_update_event_suppress_data(int *suppressed_num)
436 {
437 	zbx_vector_ptr_t	event_queries, event_data;
438 
439 	*suppressed_num = 0;
440 
441 	zbx_vector_ptr_create(&event_queries);
442 	zbx_vector_ptr_create(&event_data);
443 
444 	db_get_query_events(&event_queries, &event_data);
445 
446 	if (0 != event_queries.values_num)
447 	{
448 		zbx_db_insert_t			db_insert;
449 		char				*sql = NULL;
450 		size_t				sql_alloc = 0, sql_offset = 0;
451 		int				i, j, k;
452 		zbx_event_suppress_query_t	*query;
453 		zbx_event_suppress_data_t	*data;
454 		zbx_vector_uint64_pair_t	del_event_maintenances;
455 		zbx_vector_uint64_t		maintenanceids;
456 		zbx_uint64_pair_t		pair;
457 
458 		zbx_vector_uint64_create(&maintenanceids);
459 		zbx_vector_uint64_pair_create(&del_event_maintenances);
460 
461 		db_get_query_functions(&event_queries);
462 
463 		zbx_dc_get_running_maintenanceids(&maintenanceids);
464 
465 		DBbegin();
466 
467 		if (0 != maintenanceids.values_num && SUCCEED == zbx_db_lock_maintenanceids(&maintenanceids))
468 			zbx_dc_get_event_maintenances(&event_queries, &maintenanceids);
469 
470 		zbx_db_insert_prepare(&db_insert, "event_suppress", "event_suppressid", "eventid", "maintenanceid",
471 				"suppress_until", NULL);
472 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
473 
474 		for (i = 0; i < event_queries.values_num; i++)
475 		{
476 			query = (zbx_event_suppress_query_t *)event_queries.values[i];
477 			zbx_vector_uint64_pair_sort(&query->maintenances, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
478 
479 			k = 0;
480 
481 			if (FAIL != (j = zbx_vector_ptr_bsearch(&event_data, &query->eventid,
482 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
483 			{
484 				data = (zbx_event_suppress_data_t *)event_data.values[j];
485 				zbx_vector_uint64_pair_sort(&data->maintenances, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
486 
487 				j = 0;
488 
489 				while (j < data->maintenances.values_num && k < query->maintenances.values_num)
490 				{
491 					if (data->maintenances.values[j].first < query->maintenances.values[k].first)
492 					{
493 						pair.first = query->eventid;
494 						pair.second = data->maintenances.values[j].first;
495 						zbx_vector_uint64_pair_append(&del_event_maintenances, pair);
496 
497 						j++;
498 						continue;
499 					}
500 
501 					if (data->maintenances.values[j].first > query->maintenances.values[k].first)
502 					{
503 						if (0 == query->r_eventid)
504 						{
505 							zbx_db_insert_add_values(&db_insert, __UINT64_C(0),
506 									query->eventid,
507 									query->maintenances.values[k].first,
508 									(int)query->maintenances.values[k].second);
509 
510 							(*suppressed_num)++;
511 						}
512 
513 						k++;
514 						continue;
515 					}
516 
517 					if (data->maintenances.values[j].second != query->maintenances.values[k].second)
518 					{
519 						zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
520 								"update event_suppress"
521 								" set suppress_until=%d"
522 								" where eventid=" ZBX_FS_UI64
523 									" and maintenanceid=" ZBX_FS_UI64 ";\n",
524 									(int)query->maintenances.values[k].second,
525 									query->eventid,
526 									query->maintenances.values[k].first);
527 
528 						if (FAIL == DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
529 							goto cleanup;
530 					}
531 					j++;
532 					k++;
533 				}
534 
535 				for (;j < data->maintenances.values_num; j++)
536 				{
537 					pair.first = query->eventid;
538 					pair.second = data->maintenances.values[j].first;
539 					zbx_vector_uint64_pair_append(&del_event_maintenances, pair);
540 				}
541 			}
542 
543 			if (0 == query->r_eventid)
544 			{
545 				for (;k < query->maintenances.values_num; k++)
546 				{
547 					zbx_db_insert_add_values(&db_insert, __UINT64_C(0), query->eventid,
548 							query->maintenances.values[k].first,
549 							(int)query->maintenances.values[k].second);
550 
551 					(*suppressed_num)++;
552 				}
553 			}
554 		}
555 
556 		for (i = 0; i < del_event_maintenances.values_num; i++)
557 		{
558 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
559 					"delete from event_suppress"
560 					" where eventid=" ZBX_FS_UI64
561 						" and maintenanceid=" ZBX_FS_UI64 ";\n",
562 						del_event_maintenances.values[i].first,
563 						del_event_maintenances.values[i].second);
564 
565 			if (FAIL == DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
566 				goto cleanup;
567 		}
568 
569 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
570 
571 		if (16 < sql_offset)
572 		{
573 			if (ZBX_DB_OK > DBexecute("%s", sql))
574 				goto cleanup;
575 		}
576 
577 		zbx_db_insert_autoincrement(&db_insert, "event_suppressid");
578 		zbx_db_insert_execute(&db_insert);
579 cleanup:
580 		DBcommit();
581 
582 		zbx_db_insert_clean(&db_insert);
583 		zbx_free(sql);
584 
585 		zbx_vector_uint64_pair_destroy(&del_event_maintenances);
586 		zbx_vector_uint64_destroy(&maintenanceids);
587 	}
588 
589 	zbx_vector_ptr_clear_ext(&event_data, (zbx_clean_func_t)event_suppress_data_free);
590 	zbx_vector_ptr_destroy(&event_data);
591 
592 	zbx_vector_ptr_clear_ext(&event_queries, (zbx_clean_func_t)zbx_event_suppress_query_free);
593 	zbx_vector_ptr_destroy(&event_queries);
594 }
595 
596 /******************************************************************************
597  *                                                                            *
598  * Function: db_update_host_maintenances                                      *
599  *                                                                            *
600  * Purpose: update host maintenance parameters in cache and database          *
601  *                                                                            *
602  ******************************************************************************/
update_host_maintenances(void)603 static int	update_host_maintenances(void)
604 {
605 	zbx_vector_uint64_t	maintenanceids;
606 	zbx_vector_ptr_t	updates;
607 	int			hosts_num = 0;
608 	int			tnx_error;
609 
610 	zbx_vector_uint64_create(&maintenanceids);
611 	zbx_vector_ptr_create(&updates);
612 	zbx_vector_ptr_reserve(&updates, 100);
613 
614 	do
615 	{
616 		DBbegin();
617 
618 		if (SUCCEED == zbx_dc_get_running_maintenanceids(&maintenanceids))
619 			zbx_db_lock_maintenanceids(&maintenanceids);
620 
621 		/* host maintenance update must be called even with no maintenances running */
622 		/* to reset host maintenance status if necessary                            */
623 		zbx_dc_get_host_maintenance_updates(&maintenanceids, &updates);
624 
625 		if (0 != updates.values_num)
626 			db_update_host_maintenances(&updates);
627 
628 		if (ZBX_DB_OK == (tnx_error = DBcommit()) && 0 != (hosts_num = updates.values_num))
629 			zbx_dc_flush_host_maintenance_updates(&updates);
630 
631 		zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_ptr_free);
632 		zbx_vector_uint64_clear(&maintenanceids);
633 	}
634 	while (ZBX_DB_DOWN == tnx_error);
635 
636 	zbx_vector_ptr_destroy(&updates);
637 	zbx_vector_uint64_destroy(&maintenanceids);
638 
639 	return hosts_num;
640 }
641 
642 /******************************************************************************
643  *                                                                            *
644  * Function: timer_thread                                                     *
645  *                                                                            *
646  * Purpose: periodically processes maintenance                                *
647  *                                                                            *
648  ******************************************************************************/
ZBX_THREAD_ENTRY(timer_thread,args)649 ZBX_THREAD_ENTRY(timer_thread, args)
650 {
651 	double		sec = 0.0;
652 	int		maintenance_time = 0, update_time = 0, idle = 1, events_num, hosts_num, update;
653 	char		*info = NULL;
654 	size_t		info_alloc = 0, info_offset = 0;
655 
656 	process_type = ((zbx_thread_args_t *)args)->process_type;
657 	server_num = ((zbx_thread_args_t *)args)->server_num;
658 	process_num = ((zbx_thread_args_t *)args)->process_num;
659 
660 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
661 			server_num, get_process_type_string(process_type), process_num);
662 
663 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
664 
665 	zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
666 	zbx_strcpy_alloc(&info, &info_alloc, &info_offset, "started");
667 
668 	DBconnect(ZBX_DB_CONNECT_NORMAL);
669 
670 	while (ZBX_IS_RUNNING())
671 	{
672 		sec = zbx_time();
673 		zbx_update_env(sec);
674 
675 		if (1 == process_num)
676 		{
677 			/* start update process only when all timers have finished their updates */
678 			if (sec - maintenance_time >= ZBX_TIMER_DELAY && FAIL == zbx_dc_maintenance_check_update_flags())
679 			{
680 				zbx_setproctitle("%s #%d [%s, processing maintenances]",
681 						get_process_type_string(process_type), process_num, info);
682 
683 				update = zbx_dc_update_maintenances();
684 
685 				/* force maintenance updates at server startup */
686 				if (0 == maintenance_time)
687 					update = SUCCEED;
688 
689 				/* update hosts if there are modified (stopped, started, changed) maintenances */
690 				if (SUCCEED == update)
691 					hosts_num = update_host_maintenances();
692 				else
693 					hosts_num = 0;
694 
695 				db_remove_expired_event_suppress_data((int)sec);
696 
697 				if (SUCCEED == update)
698 				{
699 					zbx_dc_maintenance_set_update_flags();
700 					db_update_event_suppress_data(&events_num);
701 					zbx_dc_maintenance_reset_update_flag(process_num);
702 				}
703 				else
704 					events_num = 0;
705 
706 				info_offset = 0;
707 				zbx_snprintf_alloc(&info, &info_alloc, &info_offset,
708 						"updated %d hosts, suppressed %d events in " ZBX_FS_DBL " sec",
709 						hosts_num, events_num, zbx_time() - sec);
710 
711 				update_time = (int)sec;
712 			}
713 		}
714 		else if (SUCCEED == zbx_dc_maintenance_check_update_flag(process_num))
715 		{
716 			zbx_setproctitle("%s #%d [%s, processing maintenances]", get_process_type_string(process_type),
717 					process_num, info);
718 
719 			db_update_event_suppress_data(&events_num);
720 
721 			info_offset = 0;
722 			zbx_snprintf_alloc(&info, &info_alloc, &info_offset, "suppressed %d events in " ZBX_FS_DBL
723 					" sec", events_num, zbx_time() - sec);
724 
725 			update_time = (int)sec;
726 			zbx_dc_maintenance_reset_update_flag(process_num);
727 		}
728 
729 		if (maintenance_time != update_time)
730 		{
731 			update_time -= update_time % 60;
732 			maintenance_time = update_time;
733 
734 			if (0 > (idle = ZBX_TIMER_DELAY - (zbx_time() - maintenance_time)))
735 				idle = 0;
736 
737 			zbx_setproctitle("%s #%d [%s, idle %d sec]",
738 					get_process_type_string(process_type), process_num, info, idle);
739 		}
740 
741 		if (0 != idle)
742 			zbx_sleep_loop(1);
743 
744 		idle = 1;
745 	}
746 
747 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
748 
749 	while (1)
750 		zbx_sleep(SEC_PER_MIN);
751 }
752