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 "db.h"
23 #include "log.h"
24 #include "mutexs.h"
25
26 #define LOCK_ITSERVICES zbx_mutex_lock(itservices_lock)
27 #define UNLOCK_ITSERVICES zbx_mutex_unlock(itservices_lock)
28
29 static zbx_mutex_t itservices_lock = ZBX_MUTEX_NULL;
30
31 /* status update queue items */
32 typedef struct
33 {
34 /* the update source id */
35 zbx_uint64_t sourceid;
36 /* the new status */
37 int status;
38 /* timestamp */
39 int clock;
40 }
41 zbx_status_update_t;
42
43 /* Service node */
44 typedef struct
45 {
46 /* service id */
47 zbx_uint64_t serviceid;
48 /* trigger id of leaf nodes */
49 zbx_uint64_t triggerid;
50 /* the initial service status */
51 int old_status;
52 /* the calculated service status */
53 int status;
54 /* the service status calculation algorithm, see SERVICE_ALGORITHM_* defines */
55 int algorithm;
56 /* the parent nodes */
57 zbx_vector_ptr_t parents;
58 /* the child nodes */
59 zbx_vector_ptr_t children;
60 }
61 zbx_itservice_t;
62
63 /* index of services by triggerid */
64 typedef struct
65 {
66 zbx_uint64_t triggerid;
67 zbx_vector_ptr_t itservices;
68 }
69 zbx_itservice_index_t;
70
71 /* a set of services used during update session */
72 /* */
73 /* All services are stored into hashset accessed by serviceid. The services */
74 /* also are indexed by triggerid. */
75 /* The following types of services are loaded during update session: */
76 /* 1) services directly linked to the triggers with values changed */
77 /* during update session. */
78 /* 2) direct or indirect parent services of (1) */
79 /* 3) services required to calculate status of (2) and not already loaded */
80 /* as (1) or (2). */
81 /* */
82 /* In this schema: */
83 /* (1) can't have children services */
84 /* (2) will have children services */
85 /* (1) and (2) will have parent services unless it's the root service */
86 /* (3) will have neither children or parent services */
87 /* */
88 typedef struct
89 {
90 /* loaded services */
91 zbx_hashset_t itservices;
92 /* service index by triggerid */
93 zbx_hashset_t index;
94 }
95 zbx_itservices_t;
96
97 /******************************************************************************
98 * *
99 * Function: its_itservices_init *
100 * *
101 * Purpose: initializes services data set to store services during update *
102 * session *
103 * *
104 * Parameters: set - [IN] the data set to initialize *
105 * *
106 ******************************************************************************/
its_itservices_init(zbx_itservices_t * itservices)107 static void its_itservices_init(zbx_itservices_t *itservices)
108 {
109 zbx_hashset_create(&itservices->itservices, 512, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
110 zbx_hashset_create(&itservices->index, 128, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
111 }
112
113 /******************************************************************************
114 * *
115 * Function: its_itservices_clean *
116 * *
117 * Purpose: cleans services data set by releasing allocated memory *
118 * *
119 * Parameters: set - [IN] the data set to clean *
120 * *
121 ******************************************************************************/
its_itservices_clean(zbx_itservices_t * itservices)122 static void its_itservices_clean(zbx_itservices_t *itservices)
123 {
124 zbx_hashset_iter_t iter;
125 zbx_itservice_t *itservice;
126 zbx_itservice_index_t *index;
127
128 zbx_hashset_iter_reset(&itservices->index, &iter);
129
130 while (NULL != (index = (zbx_itservice_index_t *)zbx_hashset_iter_next(&iter)))
131 zbx_vector_ptr_destroy(&index->itservices);
132
133 zbx_hashset_destroy(&itservices->index);
134
135 zbx_hashset_iter_reset(&itservices->itservices, &iter);
136
137 while (NULL != (itservice = (zbx_itservice_t *)zbx_hashset_iter_next(&iter)))
138 {
139 zbx_vector_ptr_destroy(&itservice->children);
140 zbx_vector_ptr_destroy(&itservice->parents);
141 }
142
143 zbx_hashset_destroy(&itservices->itservices);
144 }
145
146 /******************************************************************************
147 * *
148 * Function: its_itservice_create *
149 * *
150 * Purpose: creates a new service node *
151 * *
152 * Parameters: itservices - [IN] the services data *
153 * serviceid - [IN] the service id *
154 * algorithm - [IN] the service status calculation mode *
155 * triggerid - [IN] the source trigger id for leaf nodes *
156 * status - [IN] the initial service status *
157 * *
158 * Return value: the created service node *
159 * *
160 ******************************************************************************/
its_itservice_create(zbx_itservices_t * itservices,zbx_uint64_t serviceid,zbx_uint64_t triggerid,int status,int algorithm)161 static zbx_itservice_t *its_itservice_create(zbx_itservices_t *itservices, zbx_uint64_t serviceid,
162 zbx_uint64_t triggerid, int status, int algorithm)
163 {
164 zbx_itservice_t itservice = {.serviceid = serviceid, .triggerid = triggerid, .old_status = status,
165 .status = status, .algorithm = algorithm}, *pitservice;
166 zbx_itservice_index_t *pindex;
167
168 zbx_vector_ptr_create(&itservice.children);
169 zbx_vector_ptr_create(&itservice.parents);
170
171 pitservice = (zbx_itservice_t *)zbx_hashset_insert(&itservices->itservices, &itservice, sizeof(itservice));
172
173 if (0 != triggerid)
174 {
175 if (NULL == (pindex = (zbx_itservice_index_t *)zbx_hashset_search(&itservices->index, &triggerid)))
176 {
177 zbx_itservice_index_t index = {.triggerid = triggerid};
178
179 zbx_vector_ptr_create(&index.itservices);
180
181 pindex = (zbx_itservice_index_t *)zbx_hashset_insert(&itservices->index, &index, sizeof(index));
182 }
183
184 zbx_vector_ptr_append(&pindex->itservices, pitservice);
185 }
186
187 return pitservice;
188 }
189
190 /******************************************************************************
191 * *
192 * Function: its_updates_append *
193 * *
194 * Purpose: adds an update to the queue *
195 * *
196 * Parameters: updates - [OUT] the update queue *
197 * sourceid - [IN] the update source id *
198 * status - [IN] the update status *
199 * clock - [IN] the update timestamp *
200 * *
201 ******************************************************************************/
its_updates_append(zbx_vector_ptr_t * updates,zbx_uint64_t sourceid,int status,int clock)202 static void its_updates_append(zbx_vector_ptr_t *updates, zbx_uint64_t sourceid, int status, int clock)
203 {
204 zbx_status_update_t *update;
205
206 update = (zbx_status_update_t *)zbx_malloc(NULL, sizeof(zbx_status_update_t));
207
208 update->sourceid = sourceid;
209 update->status = status;
210 update->clock = clock;
211
212 zbx_vector_ptr_append(updates, update);
213 }
214
zbx_status_update_free(zbx_status_update_t * update)215 static void zbx_status_update_free(zbx_status_update_t *update)
216 {
217 zbx_free(update);
218 }
219
220 /******************************************************************************
221 * *
222 * Function: its_itservices_load_children *
223 * *
224 * Purpose: loads all missing children of the specified services *
225 * *
226 * Parameters: itservices - [IN] the services data *
227 * *
228 ******************************************************************************/
its_itservices_load_children(zbx_itservices_t * itservices)229 static void its_itservices_load_children(zbx_itservices_t *itservices)
230 {
231 char *sql = NULL;
232 size_t sql_alloc = 0, sql_offset = 0;
233 DB_RESULT result;
234 DB_ROW row;
235 zbx_itservice_t *itservice, *parent;
236 zbx_uint64_t serviceid, parentid;
237 zbx_vector_uint64_t serviceids;
238 zbx_hashset_iter_t iter;
239
240 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
241
242 zbx_vector_uint64_create(&serviceids);
243
244 zbx_hashset_iter_reset(&itservices->itservices, &iter);
245
246 while (NULL != (itservice = (zbx_itservice_t *)zbx_hashset_iter_next(&iter)))
247 {
248 if (0 == itservice->triggerid)
249 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
250 }
251
252 /* check for extreme case when there are only leaf nodes */
253 if (0 == serviceids.values_num)
254 goto out;
255
256 zbx_vector_uint64_sort(&serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
257
258 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
259 "select s.serviceid,s.status,s.algorithm,sl.serviceupid"
260 " from services s,services_links sl"
261 " where s.serviceid=sl.servicedownid"
262 " and");
263 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.serviceupid", serviceids.values,
264 serviceids.values_num);
265
266 result = DBselect("%s", sql);
267
268 while (NULL != (row = DBfetch(result)))
269 {
270 ZBX_STR2UINT64(serviceid, row[0]);
271 ZBX_STR2UINT64(parentid, row[3]);
272
273 if (NULL == (parent = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &parentid)))
274 {
275 THIS_SHOULD_NEVER_HAPPEN;
276 continue;
277 }
278
279 if (NULL == (itservice = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &serviceid)))
280 itservice = its_itservice_create(itservices, serviceid, 0, atoi(row[1]), atoi(row[2]));
281
282 if (FAIL == zbx_vector_ptr_search(&parent->children, itservice, ZBX_DEFAULT_PTR_COMPARE_FUNC))
283 zbx_vector_ptr_append(&parent->children, itservice);
284 }
285 DBfree_result(result);
286
287 zbx_free(sql);
288
289 zbx_vector_uint64_destroy(&serviceids);
290 out:
291 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
292 }
293
294 /******************************************************************************
295 * *
296 * Function: its_itservices_load_parents *
297 * *
298 * Purpose: recursively loads parent nodes of the specified service until the *
299 * root node *
300 * *
301 * Parameters: itservices - [IN] the services data *
302 * serviceids - [IN] a vector containing ids of services to *
303 * load parents *
304 * *
305 ******************************************************************************/
its_itservices_load_parents(zbx_itservices_t * itservices,zbx_vector_uint64_t * serviceids)306 static void its_itservices_load_parents(zbx_itservices_t *itservices, zbx_vector_uint64_t *serviceids)
307 {
308 DB_RESULT result;
309 DB_ROW row;
310 char *sql = NULL;
311 size_t sql_alloc = 0, sql_offset = 0;
312 zbx_itservice_t *parent, *itservice;
313 zbx_uint64_t parentid, serviceid;
314
315 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
316
317 zbx_vector_uint64_sort(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
318 zbx_vector_uint64_uniq(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
319
320 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
321 "select s.serviceid,s.status,s.algorithm,sl.servicedownid"
322 " from services s,services_links sl"
323 " where s.serviceid=sl.serviceupid"
324 " and");
325 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.servicedownid", serviceids->values,
326 serviceids->values_num);
327
328 zbx_vector_uint64_clear(serviceids);
329
330 result = DBselect("%s", sql);
331
332 while (NULL != (row = DBfetch(result)))
333 {
334 ZBX_STR2UINT64(parentid, row[0]);
335 ZBX_STR2UINT64(serviceid, row[3]);
336
337 /* find the service */
338 if (NULL == (itservice = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &serviceid)))
339 {
340 THIS_SHOULD_NEVER_HAPPEN;
341 continue;
342 }
343
344 /* find/load the parent service */
345 if (NULL == (parent = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &parentid)))
346 {
347 parent = its_itservice_create(itservices, parentid, 0, atoi(row[1]), atoi(row[2]));
348 zbx_vector_uint64_append(serviceids, parent->serviceid);
349 }
350
351 /* link the service as a parent's child */
352 if (FAIL == zbx_vector_ptr_search(&itservice->parents, parent, ZBX_DEFAULT_PTR_COMPARE_FUNC))
353 zbx_vector_ptr_append(&itservice->parents, parent);
354 }
355 DBfree_result(result);
356
357 zbx_free(sql);
358
359 if (0 != serviceids->values_num)
360 its_itservices_load_parents(itservices, serviceids);
361
362 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
363 }
364
365 /******************************************************************************
366 * *
367 * Function: its_load_services_by_triggerids *
368 * *
369 * Purpose: loads services that might be affected by the specified triggerid *
370 * or are required to calculate status of loaded services *
371 * *
372 * Parameters: itservices - [IN] the services data *
373 * triggerids - [IN] the sorted list of trigger ids *
374 * *
375 ******************************************************************************/
its_load_services_by_triggerids(zbx_itservices_t * itservices,const zbx_vector_uint64_t * triggerids)376 static void its_load_services_by_triggerids(zbx_itservices_t *itservices, const zbx_vector_uint64_t *triggerids)
377 {
378 DB_RESULT result;
379 DB_ROW row;
380 zbx_uint64_t serviceid, triggerid;
381 zbx_itservice_t *itservice;
382 char *sql = NULL;
383 size_t sql_alloc = 0, sql_offset = 0;
384 zbx_vector_uint64_t serviceids;
385
386 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
387
388 zbx_vector_uint64_create(&serviceids);
389
390 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
391 "select serviceid,triggerid,status,algorithm"
392 " from services"
393 " where");
394 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num);
395
396 result = DBselect("%s", sql);
397
398 zbx_free(sql);
399
400 while (NULL != (row = DBfetch(result)))
401 {
402 ZBX_STR2UINT64(serviceid, row[0]);
403 ZBX_STR2UINT64(triggerid, row[1]);
404
405 itservice = its_itservice_create(itservices, serviceid, triggerid, atoi(row[2]), atoi(row[3]));
406
407 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
408 }
409 DBfree_result(result);
410
411 if (0 != serviceids.values_num)
412 {
413 its_itservices_load_parents(itservices, &serviceids);
414 its_itservices_load_children(itservices);
415 }
416
417 zbx_vector_uint64_destroy(&serviceids);
418
419 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
420 }
421
422 /******************************************************************************
423 * *
424 * Function: its_itservice_update_status *
425 * *
426 * Purpose: updates service and its parents statuses *
427 * *
428 * Parameters: service - [IN] the service to update *
429 * clock - [IN] the update timestamp *
430 * alarms - [OUT] the alarms update queue *
431 * *
432 * Comments: This function recalculates service status according to the *
433 * algorithm and status of the children services. If the status *
434 * has been changed, an alarm is generated and parent services *
435 * (up until the root service) are updated too. *
436 * *
437 ******************************************************************************/
its_itservice_update_status(zbx_itservice_t * itservice,int clock,zbx_vector_ptr_t * alarms)438 static void its_itservice_update_status(zbx_itservice_t *itservice, int clock, zbx_vector_ptr_t *alarms)
439 {
440 int status, i;
441
442 switch (itservice->algorithm)
443 {
444 case SERVICE_ALGORITHM_MIN:
445 status = TRIGGER_SEVERITY_COUNT;
446 for (i = 0; i < itservice->children.values_num; i++)
447 {
448 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
449
450 if (child->status < status)
451 status = child->status;
452 }
453 break;
454 case SERVICE_ALGORITHM_MAX:
455 status = 0;
456 for (i = 0; i < itservice->children.values_num; i++)
457 {
458 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
459
460 if (child->status > status)
461 status = child->status;
462 }
463 break;
464 case SERVICE_ALGORITHM_NONE:
465 goto out;
466 default:
467 zabbix_log(LOG_LEVEL_ERR, "unknown calculation algorithm of service status [%d]",
468 itservice->algorithm);
469 goto out;
470 }
471
472 if (itservice->status != status)
473 {
474 itservice->status = status;
475
476 its_updates_append(alarms, itservice->serviceid, status, clock);
477
478 /* update parent services */
479 for (i = 0; i < itservice->parents.values_num; i++)
480 its_itservice_update_status((zbx_itservice_t *)itservice->parents.values[i], clock, alarms);
481 }
482 out:
483 ;
484 }
485
486 /******************************************************************************
487 * *
488 * Function: its_updates_compare *
489 * *
490 * Purpose: used to sort service updates by source id *
491 * *
492 ******************************************************************************/
its_updates_compare(const zbx_status_update_t ** update1,const zbx_status_update_t ** update2)493 static int its_updates_compare(const zbx_status_update_t **update1, const zbx_status_update_t **update2)
494 {
495 ZBX_RETURN_IF_NOT_EQUAL((*update1)->sourceid, (*update2)->sourceid);
496
497 return 0;
498 }
499
500 /******************************************************************************
501 * *
502 * Function: its_write_status_and_alarms *
503 * *
504 * Purpose: writes service status changes and generated service alarms into *
505 * database *
506 * *
507 * Parameters: itservices - [IN] the services data *
508 * alarms - [IN] the service alarms update queue *
509 * *
510 * Return value: SUCCEED - the data was written successfully *
511 * FAIL - otherwise *
512 * *
513 ******************************************************************************/
its_write_status_and_alarms(zbx_itservices_t * itservices,zbx_vector_ptr_t * alarms)514 static int its_write_status_and_alarms(zbx_itservices_t *itservices, zbx_vector_ptr_t *alarms)
515 {
516 int i, ret = FAIL;
517 zbx_vector_ptr_t updates;
518 char *sql = NULL;
519 size_t sql_alloc = 0, sql_offset = 0;
520 zbx_uint64_t alarmid;
521 zbx_hashset_iter_t iter;
522 zbx_itservice_t *itservice;
523
524 /* get a list of service status updates that must be written to database */
525 zbx_vector_ptr_create(&updates);
526 zbx_hashset_iter_reset(&itservices->itservices, &iter);
527
528 while (NULL != (itservice = (zbx_itservice_t *)zbx_hashset_iter_next(&iter)))
529 {
530 if (itservice->old_status != itservice->status)
531 its_updates_append(&updates, itservice->serviceid, itservice->status, 0);
532 }
533
534 /* write service status changes into database */
535 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
536
537 if (0 != updates.values_num)
538 {
539 zbx_vector_ptr_sort(&updates, (zbx_compare_func_t)its_updates_compare);
540 zbx_vector_ptr_uniq(&updates, (zbx_compare_func_t)its_updates_compare);
541
542 for (i = 0; i < updates.values_num; i++)
543 {
544 zbx_status_update_t *update = (zbx_status_update_t *)updates.values[i];
545
546 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
547 "update services"
548 " set status=%d"
549 " where serviceid=" ZBX_FS_UI64 ";\n",
550 update->status, update->sourceid);
551
552 if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
553 goto out;
554 }
555 }
556
557 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
558
559 if (16 < sql_offset)
560 {
561 if (ZBX_DB_OK > DBexecute("%s", sql))
562 goto out;
563 }
564
565 ret = SUCCEED;
566
567 /* write generated service alarms into database */
568 if (0 != alarms->values_num)
569 {
570 zbx_db_insert_t db_insert;
571
572 alarmid = DBget_maxid_num("service_alarms", alarms->values_num);
573
574 zbx_db_insert_prepare(&db_insert, "service_alarms", "servicealarmid", "serviceid", "value", "clock",
575 NULL);
576
577 for (i = 0; i < alarms->values_num; i++)
578 {
579 zbx_status_update_t *update = (zbx_status_update_t *)alarms->values[i];
580
581 zbx_db_insert_add_values(&db_insert, alarmid++, update->sourceid, update->status,
582 update->clock);
583 }
584
585 ret = zbx_db_insert_execute(&db_insert);
586
587 zbx_db_insert_clean(&db_insert);
588 }
589 out:
590 zbx_free(sql);
591
592 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
593 zbx_vector_ptr_destroy(&updates);
594
595 return ret;
596 }
597
598 /******************************************************************************
599 * *
600 * Function: its_flush_updates *
601 * *
602 * Purpose: processes the service update queue *
603 * *
604 * Return value: SUCCEED - the data was written successfully *
605 * FAIL - otherwise *
606 * *
607 * Comments: The following steps are taken to process the queue: *
608 * 1) Load all services either directly referenced (with triggerid) *
609 * by update queue or dependent on those services (directly or *
610 * indirectly) or required to calculate status of any loaded *
611 * services. *
612 * 2) Apply updates to the loaded service tree. Queue new service *
613 * alarms whenever service status changes. *
614 * 3) Write the final service status changes and the generated *
615 * service alarm queue into database. *
616 * *
617 ******************************************************************************/
its_flush_updates(const zbx_vector_ptr_t * updates)618 static int its_flush_updates(const zbx_vector_ptr_t *updates)
619 {
620 int i, j, k, ret = FAIL;
621 const zbx_status_update_t *update;
622 zbx_itservices_t itservices;
623 zbx_vector_ptr_t alarms;
624 zbx_itservice_index_t *index;
625 zbx_vector_uint64_t triggerids;
626
627 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
628
629 its_itservices_init(&itservices);
630
631 zbx_vector_uint64_create(&triggerids);
632
633 for (i = 0; i < updates->values_num; i++)
634 {
635 update = (zbx_status_update_t *)updates->values[i];
636
637 zbx_vector_uint64_append(&triggerids, update->sourceid);
638 }
639
640 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
641
642 /* load all services affected by the trigger status change and */
643 /* the services that are required for resulting status calculations */
644 its_load_services_by_triggerids(&itservices, &triggerids);
645
646 zbx_vector_uint64_destroy(&triggerids);
647
648 if (0 == itservices.itservices.num_data)
649 {
650 ret = SUCCEED;
651 goto out;
652 }
653
654 zbx_vector_ptr_create(&alarms);
655
656 /* apply status updates */
657 for (i = 0; i < updates->values_num; i++)
658 {
659 update = (const zbx_status_update_t *)updates->values[i];
660
661 if (NULL == (index = (zbx_itservice_index_t *)zbx_hashset_search(&itservices.index, update)))
662 continue;
663
664 /* change the status of services based on the update */
665 for (j = 0; j < index->itservices.values_num; j++)
666 {
667 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
668
669 if (SERVICE_ALGORITHM_NONE == itservice->algorithm || itservice->status == update->status)
670 continue;
671
672 its_updates_append(&alarms, itservice->serviceid, update->status, update->clock);
673 itservice->status = update->status;
674 }
675
676 /* recalculate status of the parent services */
677 for (j = 0; j < index->itservices.values_num; j++)
678 {
679 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
680
681 /* update parent services */
682 for (k = 0; k < itservice->parents.values_num; k++)
683 its_itservice_update_status((zbx_itservice_t *)itservice->parents.values[k], update->clock, &alarms);
684 }
685 }
686
687 ret = its_write_status_and_alarms(&itservices, &alarms);
688
689 zbx_vector_ptr_clear_ext(&alarms, (zbx_clean_func_t)zbx_status_update_free);
690 zbx_vector_ptr_destroy(&alarms);
691 out:
692 its_itservices_clean(&itservices);
693
694 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
695
696 return ret;
697 }
698
699 /*
700 * Public API
701 */
702
703 /******************************************************************************
704 * *
705 * Function: DBupdate_itservices *
706 * *
707 * Purpose: updates services by applying event list *
708 * *
709 * Return value: SUCCEED - the services were updated successfully *
710 * FAIL - otherwise *
711 * *
712 ******************************************************************************/
DBupdate_itservices(const zbx_vector_ptr_t * trigger_diff)713 int DBupdate_itservices(const zbx_vector_ptr_t *trigger_diff)
714 {
715 int ret = SUCCEED;
716 zbx_vector_ptr_t updates;
717 int i;
718 const zbx_trigger_diff_t *diff;
719
720 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
721
722 zbx_vector_ptr_create(&updates);
723
724 for (i = 0; i < trigger_diff->values_num; i++)
725 {
726 diff = (zbx_trigger_diff_t *)trigger_diff->values[i];
727
728 if (0 == (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE))
729 continue;
730
731 its_updates_append(&updates, diff->triggerid, TRIGGER_VALUE_PROBLEM == diff->value ?
732 diff->priority : 0, diff->lastchange);
733 }
734
735 if (0 != updates.values_num)
736 {
737 LOCK_ITSERVICES;
738
739 do
740 {
741 DBbegin();
742
743 ret = its_flush_updates(&updates);
744 }
745 while (ZBX_DB_DOWN == DBcommit());
746
747 UNLOCK_ITSERVICES;
748
749 zbx_vector_ptr_clear_ext(&updates, zbx_ptr_free);
750 }
751
752 zbx_vector_ptr_destroy(&updates);
753
754 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
755
756 return ret;
757 }
758
759 /******************************************************************************
760 * *
761 * Function: DBremove_itservice_triggers *
762 * *
763 * Purpose: removes specified trigger ids from dependent services and reset *
764 * the status of those services to the default value (0) *
765 * *
766 * Parameters: triggerids - [IN] an array of trigger ids to remove *
767 * triggerids_num - [IN] the number of items in triggerids array *
768 * *
769 * Return value: SUCCEED - the data was written successfully *
770 * FAIL - otherwise *
771 * *
772 ******************************************************************************/
DBremove_triggers_from_itservices(zbx_uint64_t * triggerids,int triggerids_num)773 int DBremove_triggers_from_itservices(zbx_uint64_t *triggerids, int triggerids_num)
774 {
775 char *sql = NULL;
776 size_t sql_alloc = 0, sql_offset = 0;
777 zbx_vector_ptr_t updates;
778 int i, ret = FAIL, now;
779
780 if (0 == triggerids_num)
781 return SUCCEED;
782
783 now = time(NULL);
784
785 zbx_vector_ptr_create(&updates);
786
787 for (i = 0; i < triggerids_num; i++)
788 its_updates_append(&updates, triggerids[i], 0, now);
789
790 LOCK_ITSERVICES;
791
792 if (FAIL == its_flush_updates(&updates))
793 goto out;
794
795 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update services set triggerid=null,showsla=0 where");
796 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids, triggerids_num);
797
798 if (ZBX_DB_OK <= DBexecute("%s", sql))
799 ret = SUCCEED;
800
801 zbx_free(sql);
802 out:
803 UNLOCK_ITSERVICES;
804
805 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
806 zbx_vector_ptr_destroy(&updates);
807
808 return ret;
809 }
810
zbx_create_itservices_lock(char ** error)811 int zbx_create_itservices_lock(char **error)
812 {
813 return zbx_mutex_create(&itservices_lock, ZBX_MUTEX_ITSERVICES, error);
814 }
815
zbx_destroy_itservices_lock(void)816 void zbx_destroy_itservices_lock(void)
817 {
818 zbx_mutex_destroy(&itservices_lock);
819 }
820