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 const char *__function_name = "its_itservices_load_children";
232
233 char *sql = NULL;
234 size_t sql_alloc = 0, sql_offset = 0;
235 DB_RESULT result;
236 DB_ROW row;
237 zbx_itservice_t *itservice, *parent;
238 zbx_uint64_t serviceid, parentid;
239 zbx_vector_uint64_t serviceids;
240 zbx_hashset_iter_t iter;
241
242 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
243
244 zbx_vector_uint64_create(&serviceids);
245
246 zbx_hashset_iter_reset(&itservices->itservices, &iter);
247
248 while (NULL != (itservice = (zbx_itservice_t *)zbx_hashset_iter_next(&iter)))
249 {
250 if (0 == itservice->triggerid)
251 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
252 }
253
254 /* check for extreme case when there are only leaf nodes */
255 if (0 == serviceids.values_num)
256 goto out;
257
258 zbx_vector_uint64_sort(&serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
259
260 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
261 "select s.serviceid,s.status,s.algorithm,sl.serviceupid"
262 " from services s,services_links sl"
263 " where s.serviceid=sl.servicedownid"
264 " and");
265 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.serviceupid", serviceids.values,
266 serviceids.values_num);
267
268 result = DBselect("%s", sql);
269
270 while (NULL != (row = DBfetch(result)))
271 {
272 ZBX_STR2UINT64(serviceid, row[0]);
273 ZBX_STR2UINT64(parentid, row[3]);
274
275 if (NULL == (parent = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &parentid)))
276 {
277 THIS_SHOULD_NEVER_HAPPEN;
278 continue;
279 }
280
281 if (NULL == (itservice = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &serviceid)))
282 itservice = its_itservice_create(itservices, serviceid, 0, atoi(row[1]), atoi(row[2]));
283
284 if (FAIL == zbx_vector_ptr_search(&parent->children, itservice, ZBX_DEFAULT_PTR_COMPARE_FUNC))
285 zbx_vector_ptr_append(&parent->children, itservice);
286 }
287 DBfree_result(result);
288
289 zbx_free(sql);
290
291 zbx_vector_uint64_destroy(&serviceids);
292 out:
293 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
294 }
295
296 /******************************************************************************
297 * *
298 * Function: its_itservices_load_parents *
299 * *
300 * Purpose: recursively loads parent nodes of the specified service until the *
301 * root node *
302 * *
303 * Parameters: itservices - [IN] the services data *
304 * serviceids - [IN] a vector containing ids of services to *
305 * load parents *
306 * *
307 ******************************************************************************/
its_itservices_load_parents(zbx_itservices_t * itservices,zbx_vector_uint64_t * serviceids)308 static void its_itservices_load_parents(zbx_itservices_t *itservices, zbx_vector_uint64_t *serviceids)
309 {
310 const char *__function_name = "its_itservices_load_parents";
311
312 DB_RESULT result;
313 DB_ROW row;
314 char *sql = NULL;
315 size_t sql_alloc = 0, sql_offset = 0;
316 zbx_itservice_t *parent, *itservice;
317 zbx_uint64_t parentid, serviceid;
318
319 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
320
321 zbx_vector_uint64_sort(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
322 zbx_vector_uint64_uniq(serviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
323
324 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
325 "select s.serviceid,s.status,s.algorithm,sl.servicedownid"
326 " from services s,services_links sl"
327 " where s.serviceid=sl.serviceupid"
328 " and");
329 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "sl.servicedownid", serviceids->values,
330 serviceids->values_num);
331
332 zbx_vector_uint64_clear(serviceids);
333
334 result = DBselect("%s", sql);
335
336 while (NULL != (row = DBfetch(result)))
337 {
338 ZBX_STR2UINT64(parentid, row[0]);
339 ZBX_STR2UINT64(serviceid, row[3]);
340
341 /* find the service */
342 if (NULL == (itservice = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &serviceid)))
343 {
344 THIS_SHOULD_NEVER_HAPPEN;
345 continue;
346 }
347
348 /* find/load the parent service */
349 if (NULL == (parent = (zbx_itservice_t *)zbx_hashset_search(&itservices->itservices, &parentid)))
350 {
351 parent = its_itservice_create(itservices, parentid, 0, atoi(row[1]), atoi(row[2]));
352 zbx_vector_uint64_append(serviceids, parent->serviceid);
353 }
354
355 /* link the service as a parent's child */
356 if (FAIL == zbx_vector_ptr_search(&itservice->parents, parent, ZBX_DEFAULT_PTR_COMPARE_FUNC))
357 zbx_vector_ptr_append(&itservice->parents, parent);
358 }
359 DBfree_result(result);
360
361 zbx_free(sql);
362
363 if (0 != serviceids->values_num)
364 its_itservices_load_parents(itservices, serviceids);
365
366 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
367 }
368
369 /******************************************************************************
370 * *
371 * Function: its_load_services_by_triggerids *
372 * *
373 * Purpose: loads services that might be affected by the specified triggerid *
374 * or are required to calculate status of loaded services *
375 * *
376 * Parameters: itservices - [IN] the services data *
377 * triggerids - [IN] the sorted list of trigger ids *
378 * *
379 ******************************************************************************/
its_load_services_by_triggerids(zbx_itservices_t * itservices,const zbx_vector_uint64_t * triggerids)380 static void its_load_services_by_triggerids(zbx_itservices_t *itservices, const zbx_vector_uint64_t *triggerids)
381 {
382 const char *__function_name = "its_load_services_by_triggerids";
383
384 DB_RESULT result;
385 DB_ROW row;
386 zbx_uint64_t serviceid, triggerid;
387 zbx_itservice_t *itservice;
388 char *sql = NULL;
389 size_t sql_alloc = 0, sql_offset = 0;
390 zbx_vector_uint64_t serviceids;
391
392 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
393
394 zbx_vector_uint64_create(&serviceids);
395
396 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
397 "select serviceid,triggerid,status,algorithm"
398 " from services"
399 " where");
400 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num);
401
402 result = DBselect("%s", sql);
403
404 zbx_free(sql);
405
406 while (NULL != (row = DBfetch(result)))
407 {
408 ZBX_STR2UINT64(serviceid, row[0]);
409 ZBX_STR2UINT64(triggerid, row[1]);
410
411 itservice = its_itservice_create(itservices, serviceid, triggerid, atoi(row[2]), atoi(row[3]));
412
413 zbx_vector_uint64_append(&serviceids, itservice->serviceid);
414 }
415 DBfree_result(result);
416
417 if (0 != serviceids.values_num)
418 {
419 its_itservices_load_parents(itservices, &serviceids);
420 its_itservices_load_children(itservices);
421 }
422
423 zbx_vector_uint64_destroy(&serviceids);
424
425 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
426 }
427
428 /******************************************************************************
429 * *
430 * Function: its_itservice_update_status *
431 * *
432 * Purpose: updates service and its parents statuses *
433 * *
434 * Parameters: service - [IN] the service to update *
435 * clock - [IN] the update timestamp *
436 * alarms - [OUT] the alarms update queue *
437 * *
438 * Comments: This function recalculates service status according to the *
439 * algorithm and status of the children services. If the status *
440 * has been changed, an alarm is generated and parent services *
441 * (up until the root service) are updated too. *
442 * *
443 ******************************************************************************/
its_itservice_update_status(zbx_itservice_t * itservice,int clock,zbx_vector_ptr_t * alarms)444 static void its_itservice_update_status(zbx_itservice_t *itservice, int clock, zbx_vector_ptr_t *alarms)
445 {
446 int status, i;
447
448 switch (itservice->algorithm)
449 {
450 case SERVICE_ALGORITHM_MIN:
451 status = TRIGGER_SEVERITY_COUNT;
452 for (i = 0; i < itservice->children.values_num; i++)
453 {
454 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
455
456 if (child->status < status)
457 status = child->status;
458 }
459 break;
460 case SERVICE_ALGORITHM_MAX:
461 status = 0;
462 for (i = 0; i < itservice->children.values_num; i++)
463 {
464 zbx_itservice_t *child = (zbx_itservice_t *)itservice->children.values[i];
465
466 if (child->status > status)
467 status = child->status;
468 }
469 break;
470 case SERVICE_ALGORITHM_NONE:
471 goto out;
472 default:
473 zabbix_log(LOG_LEVEL_ERR, "unknown calculation algorithm of service status [%d]",
474 itservice->algorithm);
475 goto out;
476 }
477
478 if (itservice->status != status)
479 {
480 itservice->status = status;
481
482 its_updates_append(alarms, itservice->serviceid, status, clock);
483
484 /* update parent services */
485 for (i = 0; i < itservice->parents.values_num; i++)
486 its_itservice_update_status((zbx_itservice_t *)itservice->parents.values[i], clock, alarms);
487 }
488 out:
489 ;
490 }
491
492 /******************************************************************************
493 * *
494 * Function: its_updates_compare *
495 * *
496 * Purpose: used to sort service updates by source id *
497 * *
498 ******************************************************************************/
its_updates_compare(const zbx_status_update_t ** update1,const zbx_status_update_t ** update2)499 static int its_updates_compare(const zbx_status_update_t **update1, const zbx_status_update_t **update2)
500 {
501 ZBX_RETURN_IF_NOT_EQUAL((*update1)->sourceid, (*update2)->sourceid);
502
503 return 0;
504 }
505
506 /******************************************************************************
507 * *
508 * Function: its_write_status_and_alarms *
509 * *
510 * Purpose: writes service status changes and generated service alarms into *
511 * database *
512 * *
513 * Parameters: itservices - [IN] the services data *
514 * alarms - [IN] the service alarms update queue *
515 * *
516 * Return value: SUCCEED - the data was written successfully *
517 * FAIL - otherwise *
518 * *
519 ******************************************************************************/
its_write_status_and_alarms(zbx_itservices_t * itservices,zbx_vector_ptr_t * alarms)520 static int its_write_status_and_alarms(zbx_itservices_t *itservices, zbx_vector_ptr_t *alarms)
521 {
522 int i, ret = FAIL;
523 zbx_vector_ptr_t updates;
524 char *sql = NULL;
525 size_t sql_alloc = 0, sql_offset = 0;
526 zbx_uint64_t alarmid;
527 zbx_hashset_iter_t iter;
528 zbx_itservice_t *itservice;
529
530 /* get a list of service status updates that must be written to database */
531 zbx_vector_ptr_create(&updates);
532 zbx_hashset_iter_reset(&itservices->itservices, &iter);
533
534 while (NULL != (itservice = (zbx_itservice_t *)zbx_hashset_iter_next(&iter)))
535 {
536 if (itservice->old_status != itservice->status)
537 its_updates_append(&updates, itservice->serviceid, itservice->status, 0);
538 }
539
540 /* write service status changes into database */
541 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
542
543 if (0 != updates.values_num)
544 {
545 zbx_vector_ptr_sort(&updates, (zbx_compare_func_t)its_updates_compare);
546 zbx_vector_ptr_uniq(&updates, (zbx_compare_func_t)its_updates_compare);
547
548 for (i = 0; i < updates.values_num; i++)
549 {
550 zbx_status_update_t *update = (zbx_status_update_t *)updates.values[i];
551
552 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
553 "update services"
554 " set status=%d"
555 " where serviceid=" ZBX_FS_UI64 ";\n",
556 update->status, update->sourceid);
557
558 if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
559 goto out;
560 }
561 }
562
563 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
564
565 if (16 < sql_offset)
566 {
567 if (ZBX_DB_OK > DBexecute("%s", sql))
568 goto out;
569 }
570
571 ret = SUCCEED;
572
573 /* write generated service alarms into database */
574 if (0 != alarms->values_num)
575 {
576 zbx_db_insert_t db_insert;
577
578 alarmid = DBget_maxid_num("service_alarms", alarms->values_num);
579
580 zbx_db_insert_prepare(&db_insert, "service_alarms", "servicealarmid", "serviceid", "value", "clock",
581 NULL);
582
583 for (i = 0; i < alarms->values_num; i++)
584 {
585 zbx_status_update_t *update = (zbx_status_update_t *)alarms->values[i];
586
587 zbx_db_insert_add_values(&db_insert, alarmid++, update->sourceid, update->status,
588 update->clock);
589 }
590
591 ret = zbx_db_insert_execute(&db_insert);
592
593 zbx_db_insert_clean(&db_insert);
594 }
595 out:
596 zbx_free(sql);
597
598 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
599 zbx_vector_ptr_destroy(&updates);
600
601 return ret;
602 }
603
604 /******************************************************************************
605 * *
606 * Function: its_flush_updates *
607 * *
608 * Purpose: processes the service update queue *
609 * *
610 * Return value: SUCCEED - the data was written successfully *
611 * FAIL - otherwise *
612 * *
613 * Comments: The following steps are taken to process the queue: *
614 * 1) Load all services either directly referenced (with triggerid) *
615 * by update queue or dependent on those services (directly or *
616 * indirectly) or required to calculate status of any loaded *
617 * services. *
618 * 2) Apply updates to the loaded service tree. Queue new service *
619 * alarms whenever service status changes. *
620 * 3) Write the final service status changes and the generated *
621 * service alarm queue into database. *
622 * *
623 ******************************************************************************/
its_flush_updates(const zbx_vector_ptr_t * updates)624 static int its_flush_updates(const zbx_vector_ptr_t *updates)
625 {
626 const char *__function_name = "its_flush_updates";
627
628 int i, j, k, ret = FAIL;
629 const zbx_status_update_t *update;
630 zbx_itservices_t itservices;
631 zbx_vector_ptr_t alarms;
632 zbx_itservice_index_t *index;
633 zbx_vector_uint64_t triggerids;
634
635 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
636
637 its_itservices_init(&itservices);
638
639 zbx_vector_uint64_create(&triggerids);
640
641 for (i = 0; i < updates->values_num; i++)
642 {
643 update = (zbx_status_update_t *)updates->values[i];
644
645 zbx_vector_uint64_append(&triggerids, update->sourceid);
646 }
647
648 zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
649
650 /* load all services affected by the trigger status change and */
651 /* the services that are required for resulting status calculations */
652 its_load_services_by_triggerids(&itservices, &triggerids);
653
654 zbx_vector_uint64_destroy(&triggerids);
655
656 if (0 == itservices.itservices.num_data)
657 {
658 ret = SUCCEED;
659 goto out;
660 }
661
662 zbx_vector_ptr_create(&alarms);
663
664 /* apply status updates */
665 for (i = 0; i < updates->values_num; i++)
666 {
667 update = (const zbx_status_update_t *)updates->values[i];
668
669 if (NULL == (index = (zbx_itservice_index_t *)zbx_hashset_search(&itservices.index, update)))
670 continue;
671
672 /* change the status of services based on the update */
673 for (j = 0; j < index->itservices.values_num; j++)
674 {
675 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
676
677 if (SERVICE_ALGORITHM_NONE == itservice->algorithm || itservice->status == update->status)
678 continue;
679
680 its_updates_append(&alarms, itservice->serviceid, update->status, update->clock);
681 itservice->status = update->status;
682 }
683
684 /* recalculate status of the parent services */
685 for (j = 0; j < index->itservices.values_num; j++)
686 {
687 zbx_itservice_t *itservice = (zbx_itservice_t *)index->itservices.values[j];
688
689 /* update parent services */
690 for (k = 0; k < itservice->parents.values_num; k++)
691 its_itservice_update_status((zbx_itservice_t *)itservice->parents.values[k], update->clock, &alarms);
692 }
693 }
694
695 ret = its_write_status_and_alarms(&itservices, &alarms);
696
697 zbx_vector_ptr_clear_ext(&alarms, (zbx_clean_func_t)zbx_status_update_free);
698 zbx_vector_ptr_destroy(&alarms);
699 out:
700 its_itservices_clean(&itservices);
701
702 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
703
704 return ret;
705 }
706
707 /*
708 * Public API
709 */
710
711 /******************************************************************************
712 * *
713 * Function: DBupdate_itservices *
714 * *
715 * Purpose: updates services by applying event list *
716 * *
717 * Return value: SUCCEED - the services were updated successfully *
718 * FAIL - otherwise *
719 * *
720 ******************************************************************************/
DBupdate_itservices(const zbx_vector_ptr_t * trigger_diff)721 int DBupdate_itservices(const zbx_vector_ptr_t *trigger_diff)
722 {
723 const char *__function_name = "DBupdate_itservices";
724
725 int ret = SUCCEED;
726 zbx_vector_ptr_t updates;
727 int i;
728 const zbx_trigger_diff_t *diff;
729
730 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
731
732 zbx_vector_ptr_create(&updates);
733
734 for (i = 0; i < trigger_diff->values_num; i++)
735 {
736 diff = (zbx_trigger_diff_t *)trigger_diff->values[i];
737
738 if (0 == (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE))
739 continue;
740
741 its_updates_append(&updates, diff->triggerid, TRIGGER_VALUE_PROBLEM == diff->value ?
742 diff->priority : 0, diff->lastchange);
743 }
744
745 if (0 != updates.values_num)
746 {
747 LOCK_ITSERVICES;
748
749 do
750 {
751 DBbegin();
752
753 ret = its_flush_updates(&updates);
754 }
755 while (ZBX_DB_DOWN == DBcommit());
756
757 UNLOCK_ITSERVICES;
758
759 zbx_vector_ptr_clear_ext(&updates, zbx_ptr_free);
760 }
761
762 zbx_vector_ptr_destroy(&updates);
763
764 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
765
766 return ret;
767 }
768
769 /******************************************************************************
770 * *
771 * Function: DBremove_itservice_triggers *
772 * *
773 * Purpose: removes specified trigger ids from dependent services and reset *
774 * the status of those services to the default value (0) *
775 * *
776 * Parameters: triggerids - [IN] an array of trigger ids to remove *
777 * triggerids_num - [IN] the number of items in triggerids array *
778 * *
779 * Return value: SUCCEED - the data was written successfully *
780 * FAIL - otherwise *
781 * *
782 ******************************************************************************/
DBremove_triggers_from_itservices(zbx_uint64_t * triggerids,int triggerids_num)783 int DBremove_triggers_from_itservices(zbx_uint64_t *triggerids, int triggerids_num)
784 {
785 char *sql = NULL;
786 size_t sql_alloc = 0, sql_offset = 0;
787 zbx_vector_ptr_t updates;
788 int i, ret = FAIL, now;
789
790 if (0 == triggerids_num)
791 return SUCCEED;
792
793 now = time(NULL);
794
795 zbx_vector_ptr_create(&updates);
796
797 for (i = 0; i < triggerids_num; i++)
798 its_updates_append(&updates, triggerids[i], 0, now);
799
800 LOCK_ITSERVICES;
801
802 if (FAIL == its_flush_updates(&updates))
803 goto out;
804
805 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update services set triggerid=null,showsla=0 where");
806 DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids, triggerids_num);
807
808 if (ZBX_DB_OK <= DBexecute("%s", sql))
809 ret = SUCCEED;
810
811 zbx_free(sql);
812 out:
813 UNLOCK_ITSERVICES;
814
815 zbx_vector_ptr_clear_ext(&updates, (zbx_clean_func_t)zbx_status_update_free);
816 zbx_vector_ptr_destroy(&updates);
817
818 return ret;
819 }
820
zbx_create_itservices_lock(char ** error)821 int zbx_create_itservices_lock(char **error)
822 {
823 return zbx_mutex_create(&itservices_lock, ZBX_MUTEX_ITSERVICES, error);
824 }
825
zbx_destroy_itservices_lock(void)826 void zbx_destroy_itservices_lock(void)
827 {
828 zbx_mutex_destroy(&itservices_lock);
829 }
830