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