/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "timer.h" #include "zbxalgo.h" #include "zbxdb.h" #include "zbxdbhigh.h" #include "zbxstr.h" #include "zbxlog.h" #include "zbxcacheconfig.h" #include "zbxnix.h" #include "zbxself.h" #include "zbxnum.h" #include "zbxtime.h" #include "zbx_host_constants.h" #include "zbxservice.h" #include "zbxserialize.h" /* addition data for event maintenance calculations to pair with zbx_event_suppress_query_t */ typedef struct { zbx_uint64_t eventid; zbx_vector_uint64_pair_t maintenances; } zbx_event_suppress_data_t; /****************************************************************************** * * * Purpose: logs host maintenance changes * * * ******************************************************************************/ static void log_host_maintenance_update(const zbx_host_maintenance_diff_t* diff) { char *msg = NULL; size_t msg_alloc = 0, msg_offset = 0; int maintenance_off = 0; if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS)) { if (HOST_MAINTENANCE_STATUS_ON == diff->maintenance_status) { zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "putting host (" ZBX_FS_UI64 ") into", diff->hostid); } else { maintenance_off = 1; zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "taking host (" ZBX_FS_UI64 ") out of", diff->hostid); } } else zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "changing host (" ZBX_FS_UI64 ")", diff->hostid); zbx_strcpy_alloc(&msg, &msg_alloc, &msg_offset, " maintenance"); if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID) && 0 != diff->maintenanceid) zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, "(" ZBX_FS_UI64 ")", diff->maintenanceid); if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE) && 0 == maintenance_off) { const char *description[] = {"with data collection", "without data collection"}; zbx_snprintf_alloc(&msg, &msg_alloc, &msg_offset, " %s", description[diff->maintenance_type]); } zabbix_log(LOG_LEVEL_DEBUG, "%s", msg); zbx_free(msg); } /****************************************************************************** * * * Purpose: updates host maintenance properties in database * * * ******************************************************************************/ static void db_update_host_maintenances(const zbx_vector_host_maintenance_diff_ptr_t *updates) { char *sql = NULL; size_t sql_alloc = 0, sql_offset = 0; zbx_db_begin_multiple_update(&sql, &sql_alloc, &sql_offset); for (int i = 0; i < updates->values_num; i++) { char delim = ' '; const zbx_host_maintenance_diff_t *diff = updates->values[i]; zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hosts set"); if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCEID)) { if (0 != diff->maintenanceid) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenanceid=" ZBX_FS_UI64, delim, diff->maintenanceid); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenanceid=null", delim); } delim = ','; } if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_TYPE)) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_type=%u", delim, diff->maintenance_type); delim = ','; } if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_STATUS)) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_status=%u", delim, diff->maintenance_status); delim = ','; } if (0 != (diff->flags & ZBX_FLAG_HOST_MAINTENANCE_UPDATE_MAINTENANCE_FROM)) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cmaintenance_from=%d", delim, diff->maintenance_from); } zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where hostid=" ZBX_FS_UI64 ";\n", diff->hostid); if (SUCCEED != zbx_db_execute_overflowed_sql(&sql, &sql_alloc, &sql_offset)) break; if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG)) log_host_maintenance_update(diff); } zbx_db_end_multiple_update(&sql, &sql_alloc, &sql_offset); if (16 < sql_offset) zbx_db_execute("%s", sql); zbx_free(sql); } static void service_send_suppression_data(const zbx_vector_uint64_pair_t *event_maintenance, int suppressed) { unsigned char *data, *ptr; int i; zbx_uint32_t data_len; data_len = (zbx_uint32_t)((size_t)event_maintenance->values_num * sizeof(zbx_uint64_pair_t) + sizeof(int)); ptr = data = zbx_malloc(NULL, data_len); ptr += zbx_serialize_value(ptr, event_maintenance->values_num); for (i = 0; i < event_maintenance->values_num; i++) { ptr += zbx_serialize_value(ptr, event_maintenance->values[i].first); ptr += zbx_serialize_value(ptr, event_maintenance->values[i].second); } if (suppressed == 0) zbx_service_flush(ZBX_IPC_SERVICE_SERVICE_EVENTS_UNSUPPRESS, data, data_len); else zbx_service_flush(ZBX_IPC_SERVICE_SERVICE_EVENTS_SUPPRESS, data, data_len); zbx_free(data); } /****************************************************************************** * * * Purpose: removes expired event_suppress records * * * ******************************************************************************/ static void db_remove_expired_event_suppress_data(time_t now) { zbx_vector_uint64_pair_t event_maintenance; zbx_db_row_t row; zbx_db_result_t result; zbx_vector_uint64_pair_create(&event_maintenance); result = zbx_db_select("select eventid,maintenanceid from event_suppress where suppress_until<" ZBX_FS_TIME_T " and suppress_until<>0", (zbx_fs_time_t)now); while (NULL != (row = zbx_db_fetch(result))) { zbx_uint64_pair_t pair; ZBX_STR2UINT64(pair.first, row[0]); ZBX_DBROW2UINT64(pair.second, row[1]); zbx_vector_uint64_pair_append(&event_maintenance, pair); } zbx_db_free_result(result); zbx_db_begin(); zbx_db_execute("delete from event_suppress where suppress_until<" ZBX_FS_TIME_T " and suppress_until<>0", (zbx_fs_time_t)now); zbx_db_commit(); if (0 != event_maintenance.values_num && 0 != zbx_dc_get_itservices_num()) service_send_suppression_data(&event_maintenance, 0); zbx_vector_uint64_pair_destroy(&event_maintenance); } /****************************************************************************** * * * Purpose: frees event suppress data structure * * * ******************************************************************************/ static void event_suppress_data_free(zbx_event_suppress_data_t *data) { zbx_vector_uint64_pair_destroy(&data->maintenances); zbx_free(data); } ZBX_PTR_VECTOR_IMPL(event_suppress_query_ptr, zbx_event_suppress_query_t*) static int event_suppress_query_eventid_compare(const void *d1, const void *d2) { const zbx_event_suppress_query_t *ds1 = *(const zbx_event_suppress_query_t * const *)d1; const zbx_event_suppress_query_t *ds2 = *(const zbx_event_suppress_query_t * const *)d2; ZBX_RETURN_IF_NOT_EQUAL(ds1->eventid, ds2->eventid); return 0; } /****************************************************************************** * * * Purpose: fetches events that need to be queried for maintenance * * * ******************************************************************************/ static void event_queries_fetch(zbx_db_result_t result, zbx_vector_event_suppress_query_ptr_t *event_queries) { zbx_db_row_t row; zbx_uint64_t eventid; zbx_event_suppress_query_t *query = NULL; while (NULL != (row = zbx_db_fetch(result))) { ZBX_STR2UINT64(eventid, row[0]); if (NULL == query || eventid != query->eventid) { query = (zbx_event_suppress_query_t *)zbx_malloc(NULL, sizeof(zbx_event_suppress_query_t)); query->eventid = eventid; ZBX_STR2UINT64(query->triggerid, row[1]); ZBX_DBROW2UINT64(query->r_eventid, row[2]); zbx_vector_uint64_create(&query->hostids); zbx_vector_uint64_create(&query->functionids); zbx_vector_tags_ptr_create(&query->tags); zbx_vector_uint64_pair_create(&query->maintenances); zbx_vector_event_suppress_query_ptr_append(event_queries, query); } if (FAIL == zbx_db_is_null(row[3])) { zbx_tag_t *tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t)); tag->tag = zbx_strdup(NULL, row[3]); tag->value = zbx_strdup(NULL, row[4]); zbx_vector_tags_ptr_append(&query->tags, tag); } } } ZBX_PTR_VECTOR_DECL(event_suppress_data_ptr, zbx_event_suppress_data_t*) ZBX_PTR_VECTOR_IMPL(event_suppress_data_ptr, zbx_event_suppress_data_t*) static int event_suppress_data_eventid_compare(const void *d1, const void *d2) { const zbx_event_suppress_data_t *ds1 = *(const zbx_event_suppress_data_t * const *)d1; const zbx_event_suppress_data_t *ds2 = *(const zbx_event_suppress_data_t * const *)d2; ZBX_RETURN_IF_NOT_EQUAL(ds1->eventid, ds2->eventid); return 0; } /****************************************************************************** * * * Purpose: Gets open, recently resolved and resolved problems with suppress * * data from database and prepares event query, event data * * structures. * * * ******************************************************************************/ static void db_get_query_events(zbx_vector_event_suppress_query_ptr_t *event_queries, zbx_vector_event_suppress_data_ptr_t *event_data, int process_num, zbx_get_config_forks_f get_forks_cb) { zbx_db_row_t row; zbx_db_result_t result; zbx_event_suppress_data_t *data = NULL; zbx_uint64_t eventid; zbx_uint64_pair_t pair; zbx_vector_uint64_t eventids; int read_tags; const char *tag_fields, *tag_join; if (SUCCEED == (read_tags = zbx_dc_maintenance_has_tags())) { tag_fields = "t.tag,t.value"; tag_join = " left join problem_tag t on p.eventid=t.eventid"; } else { tag_fields = "null,null"; tag_join = ""; } /* get open or recently closed problems */ result = zbx_db_select("select p.eventid,p.objectid,p.r_eventid,%s" " from problem p" "%s" " where p.source=%d" " and p.object=%d" " and " ZBX_SQL_MOD(p.eventid, %d) "=%d" " order by p.eventid", tag_fields, tag_join, EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER, get_forks_cb(ZBX_PROCESS_TYPE_TIMER), process_num - 1); event_queries_fetch(result, event_queries); zbx_db_free_result(result); /* get event suppress data */ zbx_vector_uint64_create(&eventids); result = zbx_db_select("select eventid,maintenanceid,suppress_until" " from event_suppress" " where " ZBX_SQL_MOD(eventid, %d) "=%d and maintenanceid is not null" " order by eventid", get_forks_cb(ZBX_PROCESS_TYPE_TIMER), process_num - 1); while (NULL != (row = zbx_db_fetch(result))) { ZBX_STR2UINT64(eventid, row[0]); zbx_event_suppress_query_t event_query_search = {.eventid = eventid}; if (FAIL == zbx_vector_event_suppress_query_ptr_bsearch(event_queries, &event_query_search, event_suppress_query_eventid_compare)) { zbx_vector_uint64_append(&eventids, eventid); } if (NULL == data || data->eventid != eventid) { data = (zbx_event_suppress_data_t *)zbx_malloc(NULL, sizeof(zbx_event_suppress_data_t)); data->eventid = eventid; zbx_vector_uint64_pair_create(&data->maintenances); zbx_vector_event_suppress_data_ptr_append(event_data, data); } ZBX_DBROW2UINT64(pair.first, row[1]); pair.second = (zbx_uint64_t)atoi(row[2]); zbx_vector_uint64_pair_append(&data->maintenances, pair); } zbx_db_free_result(result); /* get missing event data */ if (0 != eventids.values_num) { if (SUCCEED == read_tags) { tag_fields = "t.tag,t.value"; tag_join = " left join event_tag t on e.eventid=t.eventid"; } zbx_vector_uint64_uniq(&eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); #define ZBX_EVENT_BATCH_SIZE 1000 for (int i = 0; i < eventids.values_num; i += ZBX_EVENT_BATCH_SIZE) { char *sql = NULL; size_t sql_alloc = 0, sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select e.eventid,e.objectid,er.r_eventid,%s" " from events e" " left join event_recovery er" " on e.eventid=er.eventid" "%s" " where", tag_fields, tag_join); zbx_db_add_condition_alloc(&sql, &sql_alloc, &sql_offset, "e.eventid", eventids.values + i, MIN(eventids.values_num - i, ZBX_EVENT_BATCH_SIZE)); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by e.eventid"); result = zbx_db_select("%s", sql); zbx_free(sql); event_queries_fetch(result, event_queries); zbx_db_free_result(result); } #undef ZBX_EVENT_BATCH_SIZE zbx_vector_event_suppress_query_ptr_sort(event_queries, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC); } zbx_vector_uint64_destroy(&eventids); } /****************************************************************************** * * * Purpose: Creates/Updates event suppress data to reflect latest maintenance * * changes in cache. * * * * Parameters: suppressed_num - [OUT] * * process_num - [IN] * * get_forks_cb - [IN] * * * ******************************************************************************/ static int db_update_event_suppress_data(int *suppressed_num, int process_num, zbx_get_config_forks_f get_forks_cb) { zbx_vector_event_suppress_query_ptr_t event_queries; zbx_vector_event_suppress_data_ptr_t event_data; int txn_rc = ZBX_DB_OK; *suppressed_num = 0; zbx_vector_event_suppress_query_ptr_create(&event_queries); zbx_vector_event_suppress_data_ptr_create(&event_data); db_get_query_events(&event_queries, &event_data, process_num, get_forks_cb); if (0 != event_queries.values_num) { zbx_db_insert_t db_insert; char *sql = NULL; size_t sql_alloc = 0, sql_offset = 0; int j, k; zbx_event_suppress_query_t *query; zbx_event_suppress_data_t *data; zbx_vector_uint64_pair_t del_event_maintenances, suppressed; zbx_vector_uint64_t maintenanceids; zbx_uint64_pair_t pair; zbx_vector_uint64_create(&maintenanceids); zbx_vector_uint64_pair_create(&del_event_maintenances); zbx_vector_uint64_pair_create(&suppressed); zbx_dc_get_running_maintenanceids(&maintenanceids); zbx_db_begin(); if (0 != maintenanceids.values_num && SUCCEED == zbx_db_lock_maintenanceids(&maintenanceids)) zbx_dc_get_event_maintenances(&event_queries, &maintenanceids); zbx_db_insert_prepare(&db_insert, "event_suppress", "event_suppressid", "eventid", "maintenanceid", "suppress_until", (char *)NULL); zbx_db_begin_multiple_update(&sql, &sql_alloc, &sql_offset); for (int i = 0; i < event_queries.values_num; i++) { query = event_queries.values[i]; zbx_vector_uint64_pair_sort(&query->maintenances, ZBX_DEFAULT_UINT64_COMPARE_FUNC); k = 0; zbx_event_suppress_data_t event_suppress_data_search = {.eventid = query->eventid}; if (FAIL != (j = zbx_vector_event_suppress_data_ptr_bsearch(&event_data, &event_suppress_data_search, event_suppress_data_eventid_compare))) { data = event_data.values[j]; zbx_vector_uint64_pair_sort(&data->maintenances, ZBX_DEFAULT_UINT64_COMPARE_FUNC); j = 0; while (j < data->maintenances.values_num && k < query->maintenances.values_num) { if (data->maintenances.values[j].first < query->maintenances.values[k].first) { pair.first = query->eventid; pair.second = data->maintenances.values[j].first; zbx_vector_uint64_pair_append(&del_event_maintenances, pair); j++; continue; } if (data->maintenances.values[j].first > query->maintenances.values[k].first) { if (0 == query->r_eventid) { zbx_db_insert_add_values(&db_insert, __UINT64_C(0), query->eventid, query->maintenances.values[k].first, (int)query->maintenances.values[k].second); (*suppressed_num)++; pair.first = query->eventid; pair.second = query->maintenances.values[k].first; zbx_vector_uint64_pair_append(&suppressed, pair); } k++; continue; } if (data->maintenances.values[j].second != query->maintenances.values[k].second) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update event_suppress" " set suppress_until=%d" " where eventid=" ZBX_FS_UI64 " and maintenanceid=" ZBX_FS_UI64 ";\n", (int)query->maintenances.values[k].second, query->eventid, query->maintenances.values[k].first); if (FAIL == zbx_db_execute_overflowed_sql(&sql, &sql_alloc, &sql_offset)) { goto cleanup; } } j++; k++; } for (;j < data->maintenances.values_num; j++) { pair.first = query->eventid; pair.second = data->maintenances.values[j].first; zbx_vector_uint64_pair_append(&del_event_maintenances, pair); } } if (0 == query->r_eventid) { for (;k < query->maintenances.values_num; k++) { zbx_db_insert_add_values(&db_insert, __UINT64_C(0), query->eventid, query->maintenances.values[k].first, (int)query->maintenances.values[k].second); (*suppressed_num)++; pair.first = query->eventid; pair.second = query->maintenances.values[k].first; zbx_vector_uint64_pair_append(&suppressed, pair); } } } for (int i = 0; i < del_event_maintenances.values_num; i++) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from event_suppress" " where eventid=" ZBX_FS_UI64 " and maintenanceid=" ZBX_FS_UI64 ";\n", del_event_maintenances.values[i].first, del_event_maintenances.values[i].second); if (FAIL == zbx_db_execute_overflowed_sql(&sql, &sql_alloc, &sql_offset)) goto cleanup; } zbx_db_end_multiple_update(&sql, &sql_alloc, &sql_offset); if (16 < sql_offset) { if (ZBX_DB_OK > zbx_db_execute("%s", sql)) goto cleanup; } zbx_db_insert_autoincrement(&db_insert, "event_suppressid"); zbx_db_insert_execute(&db_insert); cleanup: if (ZBX_DB_OK == (txn_rc = zbx_db_commit())) { if (0 != del_event_maintenances.values_num || 0 != suppressed.values_num) { if (0 != zbx_dc_get_itservices_num()) { if (0 != del_event_maintenances.values_num) service_send_suppression_data(&del_event_maintenances, 0); if (0 != suppressed.values_num) service_send_suppression_data(&suppressed, 1); } } } zbx_db_insert_clean(&db_insert); zbx_free(sql); zbx_vector_uint64_pair_destroy(&del_event_maintenances); zbx_vector_uint64_destroy(&maintenanceids); zbx_vector_uint64_pair_destroy(&suppressed); } zbx_vector_event_suppress_data_ptr_clear_ext(&event_data, event_suppress_data_free); zbx_vector_event_suppress_data_ptr_destroy(&event_data); zbx_vector_event_suppress_query_ptr_clear_ext(&event_queries, zbx_event_suppress_query_free); zbx_vector_event_suppress_query_ptr_destroy(&event_queries); return txn_rc; } /****************************************************************************** * * * Purpose: updates host maintenance parameters in cache and database * * * ******************************************************************************/ static int update_host_maintenances(void) { zbx_vector_uint64_t maintenanceids; zbx_vector_host_maintenance_diff_ptr_t updates; int tnx_error, hosts_num = 0; zbx_vector_uint64_create(&maintenanceids); zbx_vector_host_maintenance_diff_ptr_create(&updates); zbx_vector_host_maintenance_diff_ptr_reserve(&updates, 100); do { zbx_db_begin(); if (SUCCEED == zbx_dc_get_running_maintenanceids(&maintenanceids)) zbx_db_lock_maintenanceids(&maintenanceids); /* host maintenance update must be called even with no maintenances running */ /* to reset host maintenance status if necessary */ zbx_dc_get_host_maintenance_updates(&maintenanceids, &updates); if (0 != updates.values_num) db_update_host_maintenances(&updates); if (ZBX_DB_OK == (tnx_error = zbx_db_commit()) && 0 != (hosts_num = updates.values_num)) zbx_dc_flush_host_maintenance_updates(&updates); zbx_vector_host_maintenance_diff_ptr_clear_ext(&updates, zbx_host_maintenance_diff_free); zbx_vector_uint64_clear(&maintenanceids); } while (ZBX_DB_DOWN == tnx_error); zbx_vector_host_maintenance_diff_ptr_destroy(&updates); zbx_vector_uint64_destroy(&maintenanceids); return hosts_num; } /****************************************************************************** * * * Purpose: periodically processes maintenance * * * ******************************************************************************/ ZBX_THREAD_ENTRY(timer_thread, args) { #define ZBX_MAINTENANCE_TIMER_DELAY SEC_PER_MIN time_t schedule_time = 0, update_time = 0; char *info = NULL; size_t info_alloc = 0, info_offset = 0; const zbx_thread_info_t *thread_info = &((zbx_thread_args_t *)args)->info; int events_num, hosts_num, update, idle = 1, server_num = thread_info->server_num, process_num = thread_info->process_num; unsigned char process_type = thread_info->process_type; zbx_thread_timer_args *args_in = (zbx_thread_timer_args *)(((zbx_thread_args_t *)args)->args); zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(thread_info->program_type), server_num, get_process_type_string(process_type), process_num); zbx_update_selfmon_counter(thread_info, ZBX_PROCESS_STATE_BUSY); zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num); zbx_strcpy_alloc(&info, &info_alloc, &info_offset, "started"); zbx_db_connect(ZBX_DB_CONNECT_NORMAL); while (ZBX_IS_RUNNING()) { double sec = zbx_time(); zbx_update_env(get_process_type_string(process_type), sec); if (1 == process_num) { zbx_maintenance_timer_t maintenance_timer; if (ZBX_MAINTENANCE_TIMER_DELAY <= sec - (double)schedule_time) maintenance_timer = MAINTENANCE_TIMER_PENDING; else maintenance_timer = MAINTENANCE_TIMER_INITIALIZED; /* start update process only when all timers have finished their updates */ if ((SUCCEED == zbx_dc_maintenance_check_immediate_update() || MAINTENANCE_TIMER_PENDING == maintenance_timer) && FAIL == zbx_dc_maintenance_check_update_flags()) { zbx_setproctitle("%s #%d [%s, processing maintenances]", get_process_type_string(process_type), process_num, info); update = zbx_dc_update_maintenances(maintenance_timer); /* force maintenance updates at server startup */ if (0 == schedule_time) update = SUCCEED; /* update hosts if there are modified (stopped, started, changed) maintenances */ if (SUCCEED == update) hosts_num = update_host_maintenances(); else hosts_num = 0; if (MAINTENANCE_TIMER_PENDING == maintenance_timer) db_remove_expired_event_suppress_data((time_t)sec); if (SUCCEED == update) { zbx_dc_maintenance_set_update_flags(); while (ZBX_DB_DOWN == db_update_event_suppress_data(&events_num, process_num, args_in->get_process_forks_cb_arg)) ; zbx_dc_maintenance_reset_update_flag(process_num); } else events_num = 0; info_offset = 0; zbx_snprintf_alloc(&info, &info_alloc, &info_offset, "updated %d hosts, suppressed %d events in " ZBX_FS_DBL " sec", hosts_num, events_num, zbx_time() - sec); if (MAINTENANCE_TIMER_PENDING == maintenance_timer) update_time = (time_t)sec; } } else if (SUCCEED == zbx_dc_maintenance_check_update_flag(process_num)) { zbx_setproctitle("%s #%d [%s, processing maintenances]", get_process_type_string(process_type), process_num, info); while (ZBX_DB_DOWN == db_update_event_suppress_data(&events_num, process_num, args_in->get_process_forks_cb_arg)) ; info_offset = 0; zbx_snprintf_alloc(&info, &info_alloc, &info_offset, "suppressed %d events in " ZBX_FS_DBL " sec", events_num, zbx_time() - sec); update_time = (time_t)sec; zbx_dc_maintenance_reset_update_flag(process_num); } if (schedule_time != update_time) { update_time -= update_time % 60; schedule_time = update_time; if (0 > (idle = (int)(ZBX_MAINTENANCE_TIMER_DELAY - (zbx_time() - (double)schedule_time)))) idle = 0; zbx_setproctitle("%s #%d [%s, idle %d sec]", get_process_type_string(process_type), process_num, info, idle); } if (0 != idle) zbx_sleep_loop(thread_info, 1); idle = 1; } zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num); while (1) zbx_sleep(SEC_PER_MIN); #undef ZBX_MAINTENANCE_TIMER_DELAY }