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 "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25 
26 typedef struct
27 {
28 	zbx_uint64_t		triggerid;
29 	char			*description;
30 	char			*expression;
31 	char			*comments;
32 	char			*url;
33 	unsigned char		status;
34 	unsigned char		type;
35 	unsigned char		priority;
36 	zbx_vector_ptr_t	functions;
37 	zbx_vector_ptr_t	dependencies;
38 }
39 zbx_lld_trigger_prototype_t;
40 
41 typedef struct
42 {
43 	zbx_uint64_t		triggerid;
44 	zbx_uint64_t		parent_triggerid;
45 	char			*description;
46 	char			*description_orig;
47 	char			*expression;
48 	char			*expression_orig;
49 	char			*comments;
50 	char			*comments_orig;
51 	char			*url;
52 	char			*url_orig;
53 	zbx_vector_ptr_t	functions;
54 	zbx_vector_ptr_t	dependencies;
55 	zbx_vector_ptr_t	dependents;
56 #define ZBX_FLAG_LLD_TRIGGER_UNSET			__UINT64_C(0x00)
57 #define ZBX_FLAG_LLD_TRIGGER_DISCOVERED			__UINT64_C(0x01)
58 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION		__UINT64_C(0x02)
59 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION		__UINT64_C(0x04)
60 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE		__UINT64_C(0x08)
61 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY		__UINT64_C(0x10)
62 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS		__UINT64_C(0x20)
63 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_URL			__UINT64_C(0x40)
64 #define ZBX_FLAG_LLD_TRIGGER_UPDATE									\
65 		(ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION |	\
66 		ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE | ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY |		\
67 		ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS | ZBX_FLAG_LLD_TRIGGER_UPDATE_URL)
68 	zbx_uint64_t		flags;
69 }
70 zbx_lld_trigger_t;
71 
72 typedef struct
73 {
74 	zbx_uint64_t	functionid;
75 	zbx_uint64_t	index;
76 	zbx_uint64_t	itemid;
77 	zbx_uint64_t	itemid_orig;
78 	char		*function;
79 	char		*function_orig;
80 	char		*parameter;
81 	char		*parameter_orig;
82 #define ZBX_FLAG_LLD_FUNCTION_UNSET			__UINT64_C(0x00)
83 #define ZBX_FLAG_LLD_FUNCTION_DISCOVERED		__UINT64_C(0x01)
84 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID		__UINT64_C(0x02)
85 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION		__UINT64_C(0x04)
86 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER		__UINT64_C(0x08)
87 #define ZBX_FLAG_LLD_FUNCTION_UPDATE								\
88 		(ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID | ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION |	\
89 		ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER)
90 #define ZBX_FLAG_LLD_FUNCTION_DELETE			__UINT64_C(0x10)
91 	zbx_uint64_t	flags;
92 }
93 zbx_lld_function_t;
94 
95 typedef struct
96 {
97 	zbx_uint64_t		triggerdepid;
98 	zbx_uint64_t		triggerid_up;	/* generic trigger */
99 	zbx_lld_trigger_t	*trigger_up;	/* lld-created trigger; (null) if trigger depends on generic trigger */
100 #define ZBX_FLAG_LLD_DEPENDENCY_UNSET			__UINT64_C(0x00)
101 #define ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED		__UINT64_C(0x01)
102 #define ZBX_FLAG_LLD_DEPENDENCY_DELETE			__UINT64_C(0x02)
103 	zbx_uint64_t		flags;
104 }
105 zbx_lld_dependency_t;
106 
107 typedef struct
108 {
109 	zbx_uint64_t		parent_triggerid;
110 	zbx_uint64_t		itemid;
111 	zbx_lld_trigger_t	*trigger;
112 }
113 zbx_lld_item_trigger_t;
114 
115 typedef struct
116 {
117 	zbx_uint64_t	itemid;
118 	unsigned char	flags;
119 }
120 zbx_lld_item_t;
121 
122 /* a reference to trigger which could be either existing trigger in database or */
123 /* a just discovered trigger stored in memory                                   */
124 typedef struct
125 {
126 	/* trigger id, 0 for newly discovered triggers */
127 	zbx_uint64_t		triggerid;
128 
129 	/* trigger data, NULL for non-discovered triggers */
130 	zbx_lld_trigger_t	*trigger;
131 
132 	/* flags to mark trigger dependencies during trigger dependency validation */
133 #define ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL	0
134 #define ZBX_LLD_TRIGGER_DEPENDENCY_NEW		1
135 #define ZBX_LLD_TRIGGER_DEPENDENCY_DELETE	2
136 
137 	/* flags used to mark dependencies when trigger reference is use to store dependency links */
138 	int			flags;
139 }
140 zbx_lld_trigger_ref_t;
141 
142 /* a trigger node used to build trigger tree for dependency validation */
143 typedef struct
144 {
145 	/* trigger reference */
146 	zbx_lld_trigger_ref_t	trigger_ref;
147 
148 	/* the current iteration number, used during dependency validation */
149 	int			iter_num;
150 
151 	/* the number of dependents */
152 	int			parents;
153 
154 	/* trigger dependency list */
155 	zbx_vector_ptr_t	dependencies;
156 }
157 zbx_lld_trigger_node_t;
158 
159 /* a structure to keep information about current iteration during trigger dependencies validation */
160 typedef struct
161 {
162 	/* iteration number */
163 	int			iter_num;
164 
165 	/* the dependency (from->to) that should be removed in the case of recursive loop */
166 	zbx_lld_trigger_ref_t	*ref_from;
167 	zbx_lld_trigger_ref_t	*ref_to;
168 }
169 zbx_lld_trigger_node_iter_t;
170 
171 
lld_item_free(zbx_lld_item_t * item)172 static void	lld_item_free(zbx_lld_item_t *item)
173 {
174 	zbx_free(item);
175 }
176 
lld_function_free(zbx_lld_function_t * function)177 static void	lld_function_free(zbx_lld_function_t *function)
178 {
179 	zbx_free(function->parameter_orig);
180 	zbx_free(function->parameter);
181 	zbx_free(function->function_orig);
182 	zbx_free(function->function);
183 	zbx_free(function);
184 }
185 
lld_trigger_prototype_free(zbx_lld_trigger_prototype_t * trigger_prototype)186 static void	lld_trigger_prototype_free(zbx_lld_trigger_prototype_t *trigger_prototype)
187 {
188 	zbx_vector_ptr_clear_ext(&trigger_prototype->dependencies, zbx_ptr_free);
189 	zbx_vector_ptr_destroy(&trigger_prototype->dependencies);
190 	zbx_vector_ptr_clear_ext(&trigger_prototype->functions, (zbx_mem_free_func_t)lld_function_free);
191 	zbx_vector_ptr_destroy(&trigger_prototype->functions);
192 	zbx_free(trigger_prototype->url);
193 	zbx_free(trigger_prototype->comments);
194 	zbx_free(trigger_prototype->expression);
195 	zbx_free(trigger_prototype->description);
196 	zbx_free(trigger_prototype);
197 }
198 
lld_trigger_free(zbx_lld_trigger_t * trigger)199 static void	lld_trigger_free(zbx_lld_trigger_t *trigger)
200 {
201 	zbx_vector_ptr_destroy(&trigger->dependents);
202 	zbx_vector_ptr_clear_ext(&trigger->dependencies, zbx_ptr_free);
203 	zbx_vector_ptr_destroy(&trigger->dependencies);
204 	zbx_vector_ptr_clear_ext(&trigger->functions, (zbx_clean_func_t)lld_function_free);
205 	zbx_vector_ptr_destroy(&trigger->functions);
206 	zbx_free(trigger->url_orig);
207 	zbx_free(trigger->url);
208 	zbx_free(trigger->comments_orig);
209 	zbx_free(trigger->comments);
210 	zbx_free(trigger->expression_orig);
211 	zbx_free(trigger->expression);
212 	zbx_free(trigger->description_orig);
213 	zbx_free(trigger->description);
214 	zbx_free(trigger);
215 }
216 
217 /******************************************************************************
218  *                                                                            *
219  * Function: lld_trigger_prototypes_get                                       *
220  *                                                                            *
221  * Purpose: retrieve trigger prototypes which are inherited from the          *
222  *          discovery rule                                                    *
223  *                                                                            *
224  * Parameters: lld_ruleid         - [IN] discovery rule id                    *
225  *             trigger_prototypes - [OUT] sorted list of trigger prototypes   *
226  *                                                                            *
227  ******************************************************************************/
lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * trigger_prototypes)228 static void	lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *trigger_prototypes)
229 {
230 	DB_RESULT			result;
231 	DB_ROW				row;
232 	zbx_lld_trigger_prototype_t	*trigger_prototype;
233 
234 	result = DBselect(
235 			"select distinct t.triggerid,t.description,t.expression,t.status,t.type,t.priority,t.comments,"
236 				"t.url"
237 			" from triggers t,functions f,items i,item_discovery id"
238 			" where t.triggerid=f.triggerid"
239 				" and f.itemid=i.itemid"
240 				" and i.itemid=id.itemid"
241 				" and id.parent_itemid=" ZBX_FS_UI64,
242 			lld_ruleid);
243 
244 	/* run through trigger prototypes */
245 	while (NULL != (row = DBfetch(result)))
246 	{
247 		trigger_prototype = zbx_malloc(NULL, sizeof(zbx_lld_trigger_prototype_t));
248 
249 		ZBX_STR2UINT64(trigger_prototype->triggerid, row[0]);
250 		trigger_prototype->description = zbx_strdup(NULL, row[1]);
251 		trigger_prototype->expression = zbx_strdup(NULL, row[2]);
252 		ZBX_STR2UCHAR(trigger_prototype->status, row[3]);
253 		ZBX_STR2UCHAR(trigger_prototype->type, row[4]);
254 		ZBX_STR2UCHAR(trigger_prototype->priority, row[5]);
255 		trigger_prototype->comments = zbx_strdup(NULL, row[6]);
256 		trigger_prototype->url = zbx_strdup(NULL, row[7]);
257 
258 		zbx_vector_ptr_create(&trigger_prototype->functions);
259 		zbx_vector_ptr_create(&trigger_prototype->dependencies);
260 
261 		zbx_vector_ptr_append(trigger_prototypes, trigger_prototype);
262 	}
263 	DBfree_result(result);
264 
265 	zbx_vector_ptr_sort(trigger_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
266 }
267 
268 /******************************************************************************
269  *                                                                            *
270  * Function: lld_triggers_get                                                 *
271  *                                                                            *
272  * Purpose: retrieve triggers which were created by the specified trigger     *
273  *          prototypes                                                        *
274  *                                                                            *
275  * Parameters: trigger_prototypes - [IN] sorted list of trigger prototypes    *
276  *             triggers           - [OUT] sorted list of triggers             *
277  *                                                                            *
278  ******************************************************************************/
lld_triggers_get(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)279 static void	lld_triggers_get(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
280 {
281 	const char		*__function_name = "lld_triggers_get";
282 
283 	DB_RESULT		result;
284 	DB_ROW			row;
285 	zbx_vector_uint64_t	parent_triggerids;
286 	char			*sql = NULL;
287 	size_t			sql_alloc = 256, sql_offset = 0;
288 	int			i;
289 
290 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
291 
292 	zbx_vector_uint64_create(&parent_triggerids);
293 	zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
294 
295 	for (i = 0; i < trigger_prototypes->values_num; i++)
296 	{
297 		const zbx_lld_trigger_prototype_t	*trigger_prototype;
298 
299 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
300 
301 		zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
302 	}
303 
304 	sql = zbx_malloc(sql, sql_alloc);
305 
306 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
307 			"select td.parent_triggerid,t.triggerid,t.description,t.expression,t.type,t.priority,"
308 				"t.comments,t.url"
309 			" from triggers t,trigger_discovery td"
310 			" where t.triggerid=td.triggerid"
311 				" and");
312 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.parent_triggerid",
313 			parent_triggerids.values, parent_triggerids.values_num);
314 
315 	zbx_vector_uint64_destroy(&parent_triggerids);
316 
317 	result = DBselect("%s", sql);
318 
319 	zbx_free(sql);
320 
321 	while (NULL != (row = DBfetch(result)))
322 	{
323 		zbx_uint64_t				parent_triggerid;
324 		const zbx_lld_trigger_prototype_t	*trigger_prototype;
325 		zbx_lld_trigger_t			*trigger;
326 		int					index;
327 
328 		ZBX_STR2UINT64(parent_triggerid, row[0]);
329 
330 		if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_prototypes, &parent_triggerid,
331 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
332 		{
333 			THIS_SHOULD_NEVER_HAPPEN;
334 			continue;
335 		}
336 
337 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
338 
339 		trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
340 
341 		ZBX_STR2UINT64(trigger->triggerid, row[1]);
342 		trigger->parent_triggerid = parent_triggerid;
343 		trigger->description = zbx_strdup(NULL, row[2]);
344 		trigger->description_orig = NULL;
345 		trigger->expression = zbx_strdup(NULL, row[3]);
346 		trigger->expression_orig = NULL;
347 
348 		trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
349 
350 		if ((unsigned char)atoi(row[4]) != trigger_prototype->type)
351 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE;
352 
353 		if ((unsigned char)atoi(row[5]) != trigger_prototype->priority)
354 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY;
355 
356 		trigger->comments = zbx_strdup(NULL, row[6]);
357 		trigger->comments_orig = NULL;
358 		trigger->url = zbx_strdup(NULL, row[7]);
359 		trigger->url_orig = NULL;
360 
361 		zbx_vector_ptr_create(&trigger->functions);
362 		zbx_vector_ptr_create(&trigger->dependencies);
363 		zbx_vector_ptr_create(&trigger->dependents);
364 
365 		zbx_vector_ptr_append(triggers, trigger);
366 	}
367 	DBfree_result(result);
368 
369 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
370 
371 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
372 }
373 
374 /******************************************************************************
375  *                                                                            *
376  * Function: lld_functions_get                                                *
377  *                                                                            *
378  * Purpose: retrieve functions which are used by all triggers in the host of  *
379  *          the trigger prototype                                             *
380  *                                                                            *
381  ******************************************************************************/
lld_functions_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)382 static void	lld_functions_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
383 {
384 	const char			*__function_name = "lld_functions_get";
385 
386 	int				i;
387 	zbx_lld_trigger_prototype_t	*trigger_prototype;
388 	zbx_lld_trigger_t		*trigger;
389 	zbx_vector_uint64_t		triggerids;
390 
391 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
392 
393 	zbx_vector_uint64_create(&triggerids);
394 
395 	if (NULL != trigger_prototypes)
396 	{
397 		for (i = 0; i < trigger_prototypes->values_num; i++)
398 		{
399 			trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
400 
401 			zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
402 		}
403 	}
404 
405 	for (i = 0; i < triggers->values_num; i++)
406 	{
407 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
408 
409 		zbx_vector_uint64_append(&triggerids, trigger->triggerid);
410 	}
411 
412 	if (0 != triggerids.values_num)
413 	{
414 		DB_RESULT		result;
415 		DB_ROW			row;
416 		zbx_lld_function_t	*function;
417 		zbx_uint64_t		triggerid;
418 		char			*sql = NULL;
419 		size_t			sql_alloc = 256, sql_offset = 0;
420 		int			index;
421 
422 		zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
423 
424 		sql = zbx_malloc(sql, sql_alloc);
425 
426 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
427 				"select functionid,triggerid,itemid,function,parameter"
428 				" from functions"
429 				" where");
430 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
431 				triggerids.values, triggerids.values_num);
432 
433 		result = DBselect("%s", sql);
434 
435 		zbx_free(sql);
436 
437 		while (NULL != (row = DBfetch(result)))
438 		{
439 			function = zbx_malloc(NULL, sizeof(zbx_lld_function_t));
440 
441 			function->index = 0;
442 			ZBX_STR2UINT64(function->functionid, row[0]);
443 			ZBX_STR2UINT64(triggerid, row[1]);
444 			ZBX_STR2UINT64(function->itemid, row[2]);
445 			function->itemid_orig = 0;
446 			function->function = zbx_strdup(NULL, row[3]);
447 			function->function_orig = NULL;
448 			function->parameter = zbx_strdup(NULL, row[4]);
449 			function->parameter_orig = NULL;
450 			function->flags = ZBX_FLAG_LLD_FUNCTION_UNSET;
451 
452 			if (NULL != trigger_prototypes && FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes,
453 					&triggerid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
454 			{
455 				trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
456 
457 				zbx_vector_ptr_append(&trigger_prototype->functions, function);
458 			}
459 			else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
460 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
461 			{
462 				trigger = (zbx_lld_trigger_t *)triggers->values[index];
463 
464 				zbx_vector_ptr_append(&trigger->functions, function);
465 			}
466 			else
467 			{
468 				THIS_SHOULD_NEVER_HAPPEN;
469 				lld_function_free(function);
470 			}
471 		}
472 		DBfree_result(result);
473 
474 		if (NULL != trigger_prototypes)
475 		{
476 			for (i = 0; i < trigger_prototypes->values_num; i++)
477 			{
478 				trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
479 
480 				zbx_vector_ptr_sort(&trigger_prototype->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
481 			}
482 		}
483 
484 		for (i = 0; i < triggers->values_num; i++)
485 		{
486 			trigger = (zbx_lld_trigger_t *)triggers->values[i];
487 
488 			zbx_vector_ptr_sort(&trigger->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
489 		}
490 	}
491 
492 	zbx_vector_uint64_destroy(&triggerids);
493 
494 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
495 }
496 
497 /******************************************************************************
498  *                                                                            *
499  * Function: lld_dependencies_get                                             *
500  *                                                                            *
501  * Purpose: retrieve trigger dependencies                                     *
502  *                                                                            *
503  ******************************************************************************/
lld_dependencies_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)504 static void	lld_dependencies_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
505 {
506 	const char			*__function_name = "lld_dependencies_get";
507 
508 	DB_RESULT			result;
509 	DB_ROW				row;
510 	zbx_lld_trigger_prototype_t	*trigger_prototype;
511 	zbx_lld_trigger_t		*trigger;
512 	zbx_lld_dependency_t		*dependency;
513 	zbx_vector_uint64_t		triggerids;
514 	zbx_uint64_t			triggerid_down;
515 	char				*sql = NULL;
516 	size_t				sql_alloc = 256, sql_offset = 0;
517 	int				i, index;
518 
519 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
520 
521 	zbx_vector_uint64_create(&triggerids);
522 
523 	for (i = 0; i < trigger_prototypes->values_num; i++)
524 	{
525 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
526 
527 		zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
528 	}
529 
530 	for (i = 0; i < triggers->values_num; i++)
531 	{
532 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
533 
534 		zbx_vector_uint64_append(&triggerids, trigger->triggerid);
535 	}
536 
537 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
538 
539 	sql = zbx_malloc(sql, sql_alloc);
540 
541 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
542 			"select triggerdepid,triggerid_down,triggerid_up"
543 			" from trigger_depends"
544 			" where");
545 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid_down",
546 			triggerids.values, triggerids.values_num);
547 
548 	zbx_vector_uint64_destroy(&triggerids);
549 
550 	result = DBselect("%s", sql);
551 
552 	zbx_free(sql);
553 
554 	while (NULL != (row = DBfetch(result)))
555 	{
556 		dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
557 
558 		ZBX_STR2UINT64(dependency->triggerdepid, row[0]);
559 		ZBX_STR2UINT64(triggerid_down, row[1]);
560 		ZBX_STR2UINT64(dependency->triggerid_up, row[2]);
561 		dependency->trigger_up = NULL;
562 		dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
563 
564 		if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_down,
565 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
566 		{
567 			trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
568 
569 			zbx_vector_ptr_append(&trigger_prototype->dependencies, dependency);
570 		}
571 		else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid_down,
572 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
573 		{
574 			trigger = (zbx_lld_trigger_t *)triggers->values[index];
575 
576 			zbx_vector_ptr_append(&trigger->dependencies, dependency);
577 		}
578 		else
579 		{
580 			THIS_SHOULD_NEVER_HAPPEN;
581 			zbx_ptr_free(dependency);
582 		}
583 	}
584 	DBfree_result(result);
585 
586 	for (i = 0; i < trigger_prototypes->values_num; i++)
587 	{
588 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
589 
590 		zbx_vector_ptr_sort(&trigger_prototype->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
591 	}
592 
593 	for (i = 0; i < triggers->values_num; i++)
594 	{
595 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
596 
597 		zbx_vector_ptr_sort(&trigger->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
598 	}
599 
600 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
601 }
602 
603 /******************************************************************************
604  *                                                                            *
605  * Function: lld_items_get                                                    *
606  *                                                                            *
607  * Purpose: returns the list of items which are related to the trigger        *
608  *          prototypes                                                        *
609  *                                                                            *
610  * Parameters: trigger_prototypes - [IN] a vector of trigger prototypes       *
611  *             items              - [OUT] sorted list of items                *
612  *                                                                            *
613  ******************************************************************************/
lld_items_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * items)614 static void	lld_items_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *items)
615 {
616 	const char		*__function_name = "lld_items_get";
617 
618 	DB_RESULT		result;
619 	DB_ROW			row;
620 	zbx_lld_item_t		*item;
621 	zbx_vector_uint64_t	parent_triggerids;
622 	char			*sql = NULL;
623 	size_t			sql_alloc = 256, sql_offset = 0;
624 	int			i;
625 
626 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
627 
628 	zbx_vector_uint64_create(&parent_triggerids);
629 	zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
630 
631 	for (i = 0; i < trigger_prototypes->values_num; i++)
632 	{
633 		zbx_lld_trigger_prototype_t	*trigger_prototype;
634 
635 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
636 
637 		zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
638 	}
639 	sql = zbx_malloc(sql, sql_alloc);
640 
641 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
642 			"select distinct i.itemid,i.flags"
643 			" from items i,functions f"
644 			" where i.itemid=f.itemid"
645 				" and");
646 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "f.triggerid",
647 			parent_triggerids.values, parent_triggerids.values_num);
648 
649 	zbx_vector_uint64_destroy(&parent_triggerids);
650 
651 	result = DBselect("%s", sql);
652 
653 	zbx_free(sql);
654 
655 	while (NULL != (row = DBfetch(result)))
656 	{
657 		item = zbx_malloc(NULL, sizeof(zbx_lld_item_t));
658 
659 		ZBX_STR2UINT64(item->itemid, row[0]);
660 		ZBX_STR2UCHAR(item->flags, row[1]);
661 
662 		zbx_vector_ptr_append(items, item);
663 	}
664 	DBfree_result(result);
665 
666 	zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
667 
668 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
669 }
670 
671 /******************************************************************************
672  *                                                                            *
673  * Function: lld_trigger_get                                                  *
674  *                                                                            *
675  * Purpose: finds already existing trigger, using an item prototype and items *
676  *          already created by it                                             *
677  *                                                                            *
678  * Return value: upon successful completion return pointer to the trigger     *
679  *                                                                            *
680  ******************************************************************************/
lld_trigger_get(zbx_uint64_t parent_triggerid,zbx_hashset_t * items_triggers,const zbx_vector_ptr_t * item_links)681 static zbx_lld_trigger_t	*lld_trigger_get(zbx_uint64_t parent_triggerid, zbx_hashset_t *items_triggers,
682 		const zbx_vector_ptr_t *item_links)
683 {
684 	int	i;
685 
686 	for (i = 0; i < item_links->values_num; i++)
687 	{
688 		zbx_lld_item_trigger_t		*item_trigger, item_trigger_local;
689 		const zbx_lld_item_link_t	*item_link = (zbx_lld_item_link_t *)item_links->values[i];
690 
691 		item_trigger_local.parent_triggerid = parent_triggerid;
692 		item_trigger_local.itemid = item_link->itemid;
693 
694 		if (NULL != (item_trigger = zbx_hashset_search(items_triggers, &item_trigger_local)))
695 			return item_trigger->trigger;
696 	}
697 
698 	return NULL;
699 }
700 
lld_expression_simplify(char ** expression,zbx_vector_ptr_t * functions)701 static void	lld_expression_simplify(char **expression, zbx_vector_ptr_t *functions)
702 {
703 	const char		*__function_name = "lld_expression_simplify";
704 
705 	size_t			l, r;
706 	int			index;
707 	zbx_uint64_t		functionid, function_index = 0;
708 	zbx_lld_function_t	*function;
709 	char			buffer[ZBX_MAX_UINT64_LEN];
710 
711 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
712 
713 	for (l = 0; '\0' != (*expression)[l]; l++)
714 	{
715 		if ('{' != (*expression)[l])
716 			continue;
717 
718 		if ('$' == (*expression)[l + 1])
719 		{
720 			int	macro_r, context_l, context_r;
721 
722 			if (SUCCEED == zbx_user_macro_parse(*expression + l, &macro_r, &context_l, &context_r))
723 				l += macro_r;
724 			else
725 				l++;
726 
727 			continue;
728 		}
729 
730 		for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
731 			;
732 
733 		if ('}' != (*expression)[r])
734 			continue;
735 
736 		/* ... > 0 | {12345} + ... */
737 		/*           l     r       */
738 
739 		if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &functionid))
740 			continue;
741 
742 		if (FAIL != (index = zbx_vector_ptr_bsearch(functions, &functionid,
743 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
744 		{
745 			function = (zbx_lld_function_t *)functions->values[index];
746 
747 			if (0 == function->index)
748 				function->index = ++function_index;
749 
750 			zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->index);
751 
752 			r--;
753 			zbx_replace_string(expression, l + 1, &r, buffer);
754 			r++;
755 		}
756 
757 		l = r;
758 	}
759 
760 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
761 }
762 
lld_expression_expand(const char * expression,const zbx_vector_ptr_t * functions)763 static char	*lld_expression_expand(const char *expression, const zbx_vector_ptr_t *functions)
764 {
765 	const char		*__function_name = "lld_expression_expand";
766 
767 	size_t			l, r;
768 	int			i;
769 	zbx_uint64_t		index;
770 	char			*buffer = NULL;
771 	size_t			buffer_alloc = 64, buffer_offset = 0;
772 
773 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, expression);
774 
775 	buffer = zbx_malloc(buffer, buffer_alloc);
776 
777 	*buffer = '\0';
778 
779 	for (l = 0; '\0' != expression[l]; l++)
780 	{
781 		zbx_chrcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, expression[l]);
782 
783 		if ('{' != expression[l])
784 			continue;
785 
786 		if ('$' == expression[l + 1])
787 		{
788 			int	macro_r, context_l, context_r;
789 
790 			if (SUCCEED == zbx_user_macro_parse(expression + l, &macro_r, &context_l, &context_r))
791 				l += macro_r;
792 			else
793 				l++;
794 
795 			continue;
796 		}
797 
798 		for (r = l + 1; '\0' != expression[r] && '}' != expression[r]; r++)
799 			;
800 
801 		if ('}' != expression[r])
802 			continue;
803 
804 		/* ... > 0 | {1} + ... */
805 		/*           l r       */
806 
807 		if (SUCCEED != is_uint64_n(expression + l + 1, r - l - 1, &index))
808 			continue;
809 
810 		for (i = 0; i < functions->values_num; i++)
811 		{
812 			const zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
813 
814 			if (function->index != index)
815 				continue;
816 
817 			zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, ZBX_FS_UI64 ":%s(%s)",
818 					function->itemid, function->function, function->parameter);
819 
820 			break;
821 		}
822 
823 		l = r - 1;
824 	}
825 
826 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():'%s'", __function_name, buffer);
827 
828 	return buffer;
829 }
830 
lld_function_make(const zbx_lld_function_t * function_proto,zbx_vector_ptr_t * functions,zbx_uint64_t itemid)831 static void	lld_function_make(const zbx_lld_function_t *function_proto, zbx_vector_ptr_t *functions,
832 		zbx_uint64_t itemid)
833 {
834 	int			i;
835 	zbx_lld_function_t	*function = NULL;
836 
837 	for (i = 0; i < functions->values_num; i++)
838 	{
839 		function = (zbx_lld_function_t *)functions->values[i];
840 
841 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
842 			continue;
843 
844 		if (function->index == function_proto->index)
845 			break;
846 	}
847 
848 	if (i == functions->values_num)
849 	{
850 		function = zbx_malloc(NULL, sizeof(zbx_lld_function_t));
851 
852 		function->index = function_proto->index;
853 		function->functionid = 0;
854 		function->itemid = itemid;
855 		function->itemid_orig = 0;
856 		function->function = zbx_strdup(NULL, function_proto->function);
857 		function->function_orig = NULL;
858 		function->parameter = zbx_strdup(NULL, function_proto->parameter);
859 		function->parameter_orig = NULL;
860 		function->flags = ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
861 
862 		zbx_vector_ptr_append(functions, function);
863 	}
864 	else
865 	{
866 		if (function->itemid != itemid)
867 		{
868 			function->itemid_orig = function->itemid;
869 			function->itemid = itemid;
870 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID;
871 		}
872 
873 		if (0 != strcmp(function->function, function_proto->function))
874 		{
875 			function->function_orig = function->function;
876 			function->function = zbx_strdup(NULL, function_proto->function);
877 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION;
878 		}
879 
880 		if (0 != strcmp(function->parameter, function_proto->parameter))
881 		{
882 			function->parameter_orig = function->parameter;
883 			function->parameter = zbx_strdup(NULL, function_proto->parameter);
884 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER;
885 		}
886 
887 		function->flags |= ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
888 	}
889 }
890 
lld_functions_delete(zbx_vector_ptr_t * functions)891 static void	lld_functions_delete(zbx_vector_ptr_t *functions)
892 {
893 	int	i;
894 
895 	for (i = 0; i < functions->values_num; i++)
896 	{
897 		zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
898 
899 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
900 			continue;
901 
902 		function->flags |= ZBX_FLAG_LLD_FUNCTION_DELETE;
903 	}
904 }
905 
lld_functions_make(const zbx_vector_ptr_t * functions_proto,zbx_vector_ptr_t * functions,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * item_links)906 static int	lld_functions_make(const zbx_vector_ptr_t *functions_proto, zbx_vector_ptr_t *functions,
907 		const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *item_links)
908 {
909 	const char			*__function_name = "lld_functions_make";
910 
911 	int				i, index, ret = FAIL;
912 	const zbx_lld_function_t	*function_proto;
913 	const zbx_lld_item_t		*item_proto;
914 	const zbx_lld_item_link_t	*item_link;
915 	zbx_uint64_t			itemid;
916 
917 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
918 
919 	for (i = 0; i < functions_proto->values_num; i++)
920 	{
921 		function_proto = (zbx_lld_function_t *)functions_proto->values[i];
922 
923 		index = zbx_vector_ptr_bsearch(items, &function_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
924 
925 		if (FAIL == index)
926 			goto out;
927 
928 		item_proto = (zbx_lld_item_t *)items->values[index];
929 
930 		if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
931 		{
932 			index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid,
933 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
934 
935 			if (FAIL == index)
936 				goto out;
937 
938 			item_link = (zbx_lld_item_link_t *)item_links->values[index];
939 
940 			itemid = item_link->itemid;
941 		}
942 		else
943 			itemid = item_proto->itemid;
944 
945 		lld_function_make(function_proto, functions, itemid);
946 	}
947 
948 	lld_functions_delete(functions);
949 
950 	ret = SUCCEED;
951 out:
952 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
953 
954 	return ret;
955 }
956 
957 /******************************************************************************
958  *                                                                            *
959  * Function: lld_trigger_make                                                 *
960  *                                                                            *
961  * Purpose: create a trigger based on lld rule and add it to the list         *
962  *                                                                            *
963  ******************************************************************************/
lld_trigger_make(const zbx_lld_trigger_prototype_t * trigger_prototype,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)964 static void 	lld_trigger_make(const zbx_lld_trigger_prototype_t *trigger_prototype, zbx_vector_ptr_t *triggers,
965 		const zbx_vector_ptr_t *items, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row, char **error)
966 {
967 	const char			*__function_name = "lld_trigger_make";
968 
969 	zbx_lld_trigger_t		*trigger;
970 	char				*buffer = NULL, *expression = NULL, err[64];
971 	const struct zbx_json_parse	*jp_row = &lld_row->jp_row;
972 
973 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
974 
975 	trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links);
976 
977 	expression = zbx_strdup(expression, trigger_prototype->expression);
978 	if (SUCCEED != substitute_discovery_macros(&expression, jp_row, ZBX_MACRO_NUMERIC, err, sizeof(err)))
979 	{
980 		*error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", (NULL != trigger ? "update" : "create"), err);
981 		goto out;
982 	}
983 
984 	if (NULL != trigger)
985 	{
986 		buffer = zbx_strdup(buffer, trigger_prototype->description);
987 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
988 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
989 		if (0 != strcmp(trigger->description, buffer))
990 		{
991 			trigger->description_orig = trigger->description;
992 			trigger->description = buffer;
993 			buffer = NULL;
994 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION;
995 		}
996 
997 		if (0 != strcmp(trigger->expression, expression))
998 		{
999 			trigger->expression_orig = trigger->expression;
1000 			trigger->expression = expression;
1001 			expression = NULL;
1002 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION;
1003 		}
1004 
1005 		buffer = zbx_strdup(buffer, trigger_prototype->comments);
1006 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
1007 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1008 		if (0 != strcmp(trigger->comments, buffer))
1009 		{
1010 			trigger->comments_orig = trigger->comments;
1011 			trigger->comments = buffer;
1012 			buffer = NULL;
1013 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS;
1014 		}
1015 
1016 		buffer = zbx_strdup(buffer, trigger_prototype->url);
1017 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
1018 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1019 		if (0 != strcmp(trigger->url, buffer))
1020 		{
1021 			trigger->url_orig = trigger->url;
1022 			trigger->url = buffer;
1023 			buffer = NULL;
1024 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_URL;
1025 		}
1026 	}
1027 	else
1028 	{
1029 		trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1030 
1031 		trigger->triggerid = 0;
1032 		trigger->parent_triggerid = trigger_prototype->triggerid;
1033 
1034 		trigger->description = zbx_strdup(NULL, trigger_prototype->description);
1035 		trigger->description_orig = NULL;
1036 		substitute_discovery_macros(&trigger->description, jp_row, ZBX_MACRO_ANY, NULL, 0);
1037 		zbx_lrtrim(trigger->description, ZBX_WHITESPACE);
1038 
1039 		trigger->expression = expression;
1040 		trigger->expression_orig = NULL;
1041 		expression = NULL;
1042 
1043 		trigger->comments = zbx_strdup(NULL, trigger_prototype->comments);
1044 		trigger->comments_orig = NULL;
1045 		substitute_discovery_macros(&trigger->comments, jp_row, ZBX_MACRO_ANY, NULL, 0);
1046 		zbx_lrtrim(trigger->comments, ZBX_WHITESPACE);
1047 
1048 		trigger->url = zbx_strdup(NULL, trigger_prototype->url);
1049 		trigger->url_orig = NULL;
1050 		substitute_discovery_macros(&trigger->url, jp_row, ZBX_MACRO_ANY, NULL, 0);
1051 		zbx_lrtrim(trigger->url, ZBX_WHITESPACE);
1052 
1053 		zbx_vector_ptr_create(&trigger->functions);
1054 		zbx_vector_ptr_create(&trigger->dependencies);
1055 		zbx_vector_ptr_create(&trigger->dependents);
1056 
1057 		trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1058 
1059 		zbx_vector_ptr_append(triggers, trigger);
1060 	}
1061 
1062 	zbx_free(buffer);
1063 
1064 	if (SUCCEED != lld_functions_make(&trigger_prototype->functions, &trigger->functions, items,
1065 			&lld_row->item_links))
1066 		goto out;
1067 
1068 	trigger->flags |= ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1069 out:
1070 	zbx_free(expression);
1071 
1072 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1073 }
1074 
items_triggers_hash_func(const void * data)1075 static zbx_hash_t	items_triggers_hash_func(const void *data)
1076 {
1077 	const zbx_lld_item_trigger_t	*item_trigger = data;
1078 	zbx_hash_t			hash;
1079 
1080 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_trigger->parent_triggerid);
1081 	hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&item_trigger->itemid, sizeof(zbx_uint64_t), hash);
1082 
1083 	return hash;
1084 }
1085 
items_triggers_compare_func(const void * d1,const void * d2)1086 static int	items_triggers_compare_func(const void *d1, const void *d2)
1087 {
1088 	const zbx_lld_item_trigger_t	*item_trigger1 = d1, *item_trigger2 = d2;
1089 
1090 	ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->parent_triggerid, item_trigger2->parent_triggerid);
1091 	ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->itemid, item_trigger2->itemid);
1092 
1093 	return 0;
1094 }
1095 
lld_triggers_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * lld_rows,char ** error)1096 static void	lld_triggers_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1097 		const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows, char **error)
1098 {
1099 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
1100 	int					i, j;
1101 	zbx_hashset_t				items_triggers;
1102 	zbx_lld_trigger_t			*trigger;
1103 	const zbx_lld_function_t		*function;
1104 	zbx_lld_item_trigger_t			item_trigger;
1105 
1106 	/* used for fast search of trigger by item prototype */
1107 	zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1108 
1109 	for (i = 0; i < triggers->values_num; i++)
1110 	{
1111 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1112 
1113 		for (j = 0; j < trigger->functions.values_num; j++)
1114 		{
1115 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1116 
1117 			item_trigger.parent_triggerid = trigger->parent_triggerid;
1118 			item_trigger.itemid = function->itemid;
1119 			item_trigger.trigger = trigger;
1120 			zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1121 		}
1122 	}
1123 
1124 	for (i = 0; i < trigger_prototypes->values_num; i++)
1125 	{
1126 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1127 
1128 		for (j = 0; j < lld_rows->values_num; j++)
1129 		{
1130 			zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1131 
1132 			lld_trigger_make(trigger_prototype, triggers, items, &items_triggers, lld_row, error);
1133 		}
1134 	}
1135 
1136 	zbx_hashset_destroy(&items_triggers);
1137 
1138 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1139 }
1140 
1141 /******************************************************************************
1142  *                                                                            *
1143  * Function: lld_trigger_dependency_make                                      *
1144  *                                                                            *
1145  * Purpose: create a trigger dependencies                                     *
1146  *                                                                            *
1147  ******************************************************************************/
lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t * trigger_prototype,const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * items,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)1148 static void 	lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t *trigger_prototype,
1149 		const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *items,
1150 		zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row, char **error)
1151 {
1152 	const char				*__function_name = "lld_trigger_dependency_make";
1153 
1154 	zbx_lld_trigger_t			*trigger, *dep_trigger;
1155 	const zbx_lld_trigger_prototype_t	*dep_trigger_prototype;
1156 	zbx_lld_dependency_t			*dependency;
1157 	zbx_uint64_t				triggerid_up;
1158 	int					i, j, index;
1159 
1160 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1161 
1162 	if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1163 		goto out;
1164 
1165 	for (i = 0; i < trigger_prototype->dependencies.values_num; i++)
1166 	{
1167 		triggerid_up = ((zbx_lld_dependency_t *)trigger_prototype->dependencies.values[i])->triggerid_up;
1168 
1169 		index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_up, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1170 
1171 		if (FAIL != index)
1172 		{
1173 			/* creating trigger dependency based on trigger prototype */
1174 
1175 			dep_trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1176 
1177 			dep_trigger = lld_trigger_get(dep_trigger_prototype->triggerid, items_triggers,
1178 					&lld_row->item_links);
1179 
1180 			if (NULL != dep_trigger)
1181 			{
1182 				if (0 == dep_trigger->triggerid)
1183 				{
1184 					dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1185 
1186 					dependency->triggerdepid = 0;
1187 					dependency->triggerid_up = 0;
1188 
1189 					zbx_vector_ptr_append(&trigger->dependencies, dependency);
1190 				}
1191 				else
1192 				{
1193 					for (j = 0; j < trigger->dependencies.values_num; j++)
1194 					{
1195 						dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1196 
1197 						if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1198 							continue;
1199 
1200 						if (dependency->triggerid_up == dep_trigger->triggerid)
1201 							break;
1202 					}
1203 
1204 					if (j == trigger->dependencies.values_num)
1205 					{
1206 						dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1207 
1208 						dependency->triggerdepid = 0;
1209 						dependency->triggerid_up = dep_trigger->triggerid;
1210 
1211 						zbx_vector_ptr_append(&trigger->dependencies, dependency);
1212 					}
1213 				}
1214 
1215 				zbx_vector_ptr_append(&dep_trigger->dependents, trigger);
1216 
1217 				dependency->trigger_up = dep_trigger;
1218 				dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1219 			}
1220 			else
1221 			{
1222 				*error = zbx_strdcatf(*error, "Cannot create dependency on trigger \"%s\".\n",
1223 						trigger->description);
1224 			}
1225 		}
1226 		else
1227 		{
1228 			/* creating trigger dependency based on generic trigger */
1229 
1230 			for (j = 0; j < trigger->dependencies.values_num; j++)
1231 			{
1232 				dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1233 
1234 				if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1235 					continue;
1236 
1237 				if (dependency->triggerid_up == triggerid_up)
1238 					break;
1239 			}
1240 
1241 			if (j == trigger->dependencies.values_num)
1242 			{
1243 				dependency = zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1244 
1245 				dependency->triggerdepid = 0;
1246 				dependency->triggerid_up = triggerid_up;
1247 				dependency->trigger_up = NULL;
1248 
1249 				zbx_vector_ptr_append(&trigger->dependencies, dependency);
1250 			}
1251 
1252 			dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1253 		}
1254 	}
1255 out:
1256 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1257 }
1258 
lld_trigger_dependencies_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * items,const zbx_vector_ptr_t * lld_rows,char ** error)1259 static void	lld_trigger_dependencies_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1260 		zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows, char **error)
1261 {
1262 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
1263 	int				i, j;
1264 	zbx_hashset_t			items_triggers;
1265 	zbx_lld_trigger_t		*trigger;
1266 	zbx_lld_function_t		*function;
1267 	zbx_lld_item_trigger_t		item_trigger;
1268 	zbx_lld_dependency_t		*dependency;
1269 
1270 	for (i = 0; i < trigger_prototypes->values_num; i++)
1271 	{
1272 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1273 
1274 		if (0 != trigger_prototype->dependencies.values_num)
1275 			break;
1276 	}
1277 
1278 	for (j = 0; j < triggers->values_num; j++)
1279 	{
1280 		trigger = (zbx_lld_trigger_t *)triggers->values[j];
1281 
1282 		if (0 != trigger->dependencies.values_num)
1283 			break;
1284 	}
1285 
1286 	/* all trigger prototypes and triggers have no dependencies */
1287 	if (i == trigger_prototypes->values_num && j == triggers->values_num)
1288 		return;
1289 
1290 	/* used for fast search of trigger by item prototype */
1291 	zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1292 
1293 	for (i = 0; i < triggers->values_num; i++)
1294 	{
1295 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1296 
1297 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1298 			continue;
1299 
1300 		for (j = 0; j < trigger->functions.values_num; j++)
1301 		{
1302 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1303 
1304 			item_trigger.parent_triggerid = trigger->parent_triggerid;
1305 			item_trigger.itemid = function->itemid;
1306 			item_trigger.trigger = trigger;
1307 			zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1308 		}
1309 	}
1310 
1311 	for (i = 0; i < trigger_prototypes->values_num; i++)
1312 	{
1313 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1314 
1315 		for (j = 0; j < lld_rows->values_num; j++)
1316 		{
1317 			zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1318 
1319 			lld_trigger_dependency_make(trigger_prototype, trigger_prototypes, triggers, items,
1320 					&items_triggers, lld_row, error);
1321 		}
1322 	}
1323 
1324 	/* marking dependencies which will be deleted */
1325 	for (i = 0; i < triggers->values_num; i++)
1326 	{
1327 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1328 
1329 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1330 			continue;
1331 
1332 		for (j = 0; j < trigger->dependencies.values_num; j++)
1333 		{
1334 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1335 
1336 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1337 				dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DELETE;
1338 		}
1339 	}
1340 
1341 	zbx_hashset_destroy(&items_triggers);
1342 
1343 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1344 }
1345 
1346 /******************************************************************************
1347  *                                                                            *
1348  * Function: lld_validate_trigger_field                                       *
1349  *                                                                            *
1350  ******************************************************************************/
lld_validate_trigger_field(zbx_lld_trigger_t * trigger,char ** field,char ** field_orig,zbx_uint64_t flag,size_t field_len,char ** error)1351 static void	lld_validate_trigger_field(zbx_lld_trigger_t *trigger, char **field, char **field_orig,
1352 		zbx_uint64_t flag, size_t field_len, char **error)
1353 {
1354 	if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1355 		return;
1356 
1357 	/* only new triggers or triggers with changed data will be validated */
1358 	if (0 != trigger->triggerid && 0 == (trigger->flags & flag))
1359 		return;
1360 
1361 	if (SUCCEED != zbx_is_utf8(*field))
1362 	{
1363 		zbx_replace_invalid_utf8(*field);
1364 		*error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" has invalid UTF-8 sequence.\n",
1365 				(0 != trigger->triggerid ? "update" : "create"), *field);
1366 	}
1367 	else if (zbx_strlen_utf8(*field) > field_len)
1368 	{
1369 		*error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" is too long.\n",
1370 				(0 != trigger->triggerid ? "update" : "create"), *field);
1371 	}
1372 	else if (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION == flag && '\0' == **field)
1373 	{
1374 		*error = zbx_strdcatf(*error, "Cannot %s trigger: name is empty.\n",
1375 				(0 != trigger->triggerid ? "update" : "create"));
1376 	}
1377 	else
1378 		return;
1379 
1380 	if (0 != trigger->triggerid)
1381 		lld_field_str_rollback(field, field_orig, &trigger->flags, flag);
1382 	else
1383 		trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1384 }
1385 
1386 /******************************************************************************
1387  *                                                                            *
1388  * Function: lld_trigger_changed                                              *
1389  *                                                                            *
1390  * Return value: returns SUCCEED if a trigger description or expression has   *
1391  *               been changed; FAIL - otherwise                               *
1392  *                                                                            *
1393  ******************************************************************************/
lld_trigger_changed(const zbx_lld_trigger_t * trigger)1394 static int	lld_trigger_changed(const zbx_lld_trigger_t *trigger)
1395 {
1396 	int			i;
1397 	zbx_lld_function_t	*function;
1398 
1399 	if (0 == trigger->triggerid)
1400 		return SUCCEED;
1401 
1402 	if (0 != (trigger->flags & (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION)))
1403 		return SUCCEED;
1404 
1405 	for (i = 0; i < trigger->functions.values_num; i++)
1406 	{
1407 		function = (zbx_lld_function_t *)trigger->functions.values[i];
1408 
1409 		if (0 == function->functionid)
1410 		{
1411 			THIS_SHOULD_NEVER_HAPPEN;
1412 			return SUCCEED;
1413 		}
1414 
1415 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1416 			return SUCCEED;
1417 	}
1418 
1419 	return FAIL;
1420 }
1421 
1422 /******************************************************************************
1423  *                                                                            *
1424  * Function: lld_triggers_equal                                               *
1425  *                                                                            *
1426  * Return value: returns SUCCEED if descriptions and expressions of           *
1427  *               the triggers are identical; FAIL - otherwise                 *
1428  *                                                                            *
1429  ******************************************************************************/
lld_triggers_equal(const zbx_lld_trigger_t * trigger,const zbx_lld_trigger_t * trigger_b)1430 static int	lld_triggers_equal(const zbx_lld_trigger_t *trigger, const zbx_lld_trigger_t *trigger_b)
1431 {
1432 	const char	*__function_name = "lld_triggers_equal";
1433 
1434 	int		ret = FAIL;
1435 
1436 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1437 
1438 	if (0 == strcmp(trigger->description, trigger_b->description))
1439 	{
1440 		char	*expression, *expression_b;
1441 
1442 		expression = lld_expression_expand(trigger->expression, &trigger->functions);
1443 		expression_b = lld_expression_expand(trigger_b->expression, &trigger_b->functions);
1444 
1445 		if (0 == strcmp(expression, expression_b))
1446 			ret = SUCCEED;
1447 
1448 		zbx_free(expression);
1449 		zbx_free(expression_b);
1450 	}
1451 
1452 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1453 
1454 	return ret;
1455 }
1456 
1457 /******************************************************************************
1458  *                                                                            *
1459  * Function: lld_triggers_validate                                            *
1460  *                                                                            *
1461  * Parameters: triggers - [IN] sorted list of triggers                        *
1462  *                                                                            *
1463  ******************************************************************************/
lld_triggers_validate(zbx_uint64_t hostid,zbx_vector_ptr_t * triggers,char ** error)1464 static void	lld_triggers_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *triggers, char **error)
1465 {
1466 	const char		*__function_name = "lld_triggers_validate";
1467 
1468 	int			i, j, k;
1469 	zbx_lld_trigger_t	*trigger;
1470 	zbx_lld_function_t	*function;
1471 	zbx_vector_uint64_t	triggerids;
1472 	zbx_vector_str_t	descriptions;
1473 
1474 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1475 
1476 	zbx_vector_uint64_create(&triggerids);
1477 	zbx_vector_str_create(&descriptions);
1478 
1479 	/* checking a validity of the fields */
1480 
1481 	for (i = 0; i < triggers->values_num; i++)
1482 	{
1483 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1484 
1485 		lld_validate_trigger_field(trigger, &trigger->description, &trigger->description_orig,
1486 				ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION, TRIGGER_DESCRIPTION_LEN, error);
1487 		lld_validate_trigger_field(trigger, &trigger->comments, &trigger->comments_orig,
1488 				ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS, TRIGGER_COMMENTS_LEN, error);
1489 		lld_validate_trigger_field(trigger, &trigger->url, &trigger->url_orig,
1490 				ZBX_FLAG_LLD_TRIGGER_UPDATE_URL, TRIGGER_URL_LEN, error);
1491 	}
1492 
1493 	/* checking duplicated triggers in DB */
1494 
1495 	for (i = 0; i < triggers->values_num; i++)
1496 	{
1497 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1498 
1499 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1500 			continue;
1501 
1502 		if (0 != trigger->triggerid)
1503 		{
1504 			zbx_vector_uint64_append(&triggerids, trigger->triggerid);
1505 
1506 			if (SUCCEED != lld_trigger_changed(trigger))
1507 				continue;
1508 		}
1509 
1510 		zbx_vector_str_append(&descriptions, trigger->description);
1511 	}
1512 
1513 	if (0 != descriptions.values_num)
1514 	{
1515 		char			*sql = NULL;
1516 		size_t			sql_alloc = 256, sql_offset = 0;
1517 		DB_RESULT		result;
1518 		DB_ROW			row;
1519 		zbx_vector_ptr_t	db_triggers;
1520 		zbx_lld_trigger_t	*db_trigger;
1521 
1522 		zbx_vector_ptr_create(&db_triggers);
1523 
1524 		zbx_vector_str_sort(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
1525 		zbx_vector_str_uniq(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
1526 
1527 		sql = zbx_malloc(sql, sql_alloc);
1528 
1529 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1530 				"select distinct t.triggerid,t.description,t.expression"
1531 				" from triggers t,functions f,items i"
1532 				" where t.triggerid=f.triggerid"
1533 					" and f.itemid=i.itemid"
1534 					" and i.hostid=" ZBX_FS_UI64
1535 					" and",
1536 				hostid);
1537 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.description",
1538 				(const char **)descriptions.values, descriptions.values_num);
1539 
1540 		if (0 != triggerids.values_num)
1541 		{
1542 			zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1543 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
1544 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid",
1545 					triggerids.values, triggerids.values_num);
1546 		}
1547 
1548 		result = DBselect("%s", sql);
1549 
1550 		while (NULL != (row = DBfetch(result)))
1551 		{
1552 			db_trigger = zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1553 
1554 			ZBX_STR2UINT64(db_trigger->triggerid, row[0]);
1555 			db_trigger->description = zbx_strdup(NULL, row[1]);
1556 			db_trigger->description_orig = NULL;
1557 			db_trigger->expression = zbx_strdup(NULL, row[2]);
1558 			db_trigger->expression_orig = NULL;
1559 			db_trigger->comments = NULL;
1560 			db_trigger->comments_orig = NULL;
1561 			db_trigger->url = NULL;
1562 			db_trigger->url_orig = NULL;
1563 			db_trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1564 
1565 			zbx_vector_ptr_create(&db_trigger->functions);
1566 			zbx_vector_ptr_create(&db_trigger->dependencies);
1567 			zbx_vector_ptr_create(&db_trigger->dependents);
1568 
1569 			zbx_vector_ptr_append(&db_triggers, db_trigger);
1570 		}
1571 		DBfree_result(result);
1572 
1573 		zbx_vector_ptr_sort(&db_triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1574 
1575 		lld_functions_get(NULL, &db_triggers);
1576 
1577 		for (i = 0; i < db_triggers.values_num; i++)
1578 		{
1579 			db_trigger = (zbx_lld_trigger_t *)db_triggers.values[i];
1580 
1581 			lld_expression_simplify(&db_trigger->expression, &db_trigger->functions);
1582 
1583 			for (j = 0; j < triggers->values_num; j++)
1584 			{
1585 				trigger = (zbx_lld_trigger_t *)triggers->values[j];
1586 
1587 				if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1588 					continue;
1589 
1590 				if (SUCCEED != lld_triggers_equal(trigger, db_trigger))
1591 					continue;
1592 
1593 				*error = zbx_strdcatf(*error, "Cannot %s trigger: trigger \"%s\" already exists.\n",
1594 						(0 != trigger->triggerid ? "update" : "create"), trigger->description);
1595 
1596 				if (0 != trigger->triggerid)
1597 				{
1598 					lld_field_str_rollback(&trigger->description, &trigger->description_orig,
1599 							&trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION);
1600 
1601 					lld_field_str_rollback(&trigger->expression, &trigger->expression_orig,
1602 							&trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION);
1603 
1604 					for (k = 0; k < trigger->functions.values_num; k++)
1605 					{
1606 						function = (zbx_lld_function_t *)trigger->functions.values[k];
1607 
1608 						if (0 != function->functionid)
1609 						{
1610 							lld_field_uint64_rollback(&function->itemid,
1611 									&function->itemid_orig,
1612 									&function->flags,
1613 									ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID);
1614 
1615 							lld_field_str_rollback(&function->function,
1616 									&function->function_orig,
1617 									&function->flags,
1618 									ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION);
1619 
1620 							lld_field_str_rollback(&function->parameter,
1621 									&function->parameter_orig,
1622 									&function->flags,
1623 									ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER);
1624 
1625 							function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DELETE;
1626 						}
1627 						else
1628 							function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1629 					}
1630 				}
1631 				else
1632 					trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1633 
1634 				break;	/* only one same trigger can be here */
1635 			}
1636 		}
1637 
1638 		zbx_vector_ptr_clear_ext(&db_triggers, (zbx_clean_func_t)lld_trigger_free);
1639 		zbx_vector_ptr_destroy(&db_triggers);
1640 
1641 		zbx_free(sql);
1642 	}
1643 
1644 	zbx_vector_str_destroy(&descriptions);
1645 	zbx_vector_uint64_destroy(&triggerids);
1646 
1647 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1648 }
1649 
1650 /******************************************************************************
1651  *                                                                            *
1652  * Function: lld_expression_create                                            *
1653  *                                                                            *
1654  * Purpose: transforms the simple trigger expression to the DB format         *
1655  *                                                                            *
1656  * Example:                                                                   *
1657  *                                                                            *
1658  *     "{1} > 5" => "{84756} > 5"                                             *
1659  *       ^            ^                                                       *
1660  *       |            functionid from the database                            *
1661  *       internal function index                                              *
1662  *                                                                            *
1663  ******************************************************************************/
lld_expression_create(char ** expression,const zbx_vector_ptr_t * functions)1664 static void	lld_expression_create(char **expression, const zbx_vector_ptr_t *functions)
1665 {
1666 	const char		*__function_name = "lld_expression_create";
1667 
1668 	size_t			l, r;
1669 	int			i;
1670 	zbx_uint64_t		function_index;
1671 	char			buffer[ZBX_MAX_UINT64_LEN];
1672 
1673 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
1674 
1675 	for (l = 0; '\0' != (*expression)[l]; l++)
1676 	{
1677 		if ('{' != (*expression)[l])
1678 			continue;
1679 
1680 		if ('$' == (*expression)[l + 1])
1681 		{
1682 			int	macro_r, context_l, context_r;
1683 
1684 			if (SUCCEED == zbx_user_macro_parse(*expression + l, &macro_r, &context_l, &context_r))
1685 				l += macro_r;
1686 			else
1687 				l++;
1688 
1689 			continue;
1690 		}
1691 
1692 		for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
1693 			;
1694 
1695 		if ('}' != (*expression)[r])
1696 			continue;
1697 
1698 		/* ... > 0 | {1} + ... */
1699 		/*           l r       */
1700 
1701 		if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &function_index))
1702 			continue;
1703 
1704 		for (i = 0; i < functions->values_num; i++)
1705 		{
1706 			const zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
1707 
1708 			if (function->index != function_index)
1709 				continue;
1710 
1711 			zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->functionid);
1712 
1713 			r--;
1714 			zbx_replace_string(expression, l + 1, &r, buffer);
1715 			r++;
1716 
1717 			break;
1718 		}
1719 
1720 		l = r;
1721 	}
1722 
1723 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
1724 }
1725 
1726 /******************************************************************************
1727  *                                                                            *
1728  * Function: lld_triggers_save                                                *
1729  *                                                                            *
1730  * Purpose: add or update triggers in database based on discovery rule        *
1731  *                                                                            *
1732  * Parameters: hostid            - [IN] parent host id                        *
1733  *             lld_triggers_save - [IN] trigger prototypes                    *
1734  *             triggers          - [IN/OUT] triggers to save                  *
1735  *                                                                            *
1736  * Return value: SUCCEED - if triggers was successfully saved or saving       *
1737  *                         was not necessary                                  *
1738  *               FAIL    - triggers cannot be saved                           *
1739  *                                                                            *
1740  ******************************************************************************/
lld_triggers_save(zbx_uint64_t hostid,const zbx_vector_ptr_t * trigger_prototypes,const zbx_vector_ptr_t * triggers)1741 static int	lld_triggers_save(zbx_uint64_t hostid, const zbx_vector_ptr_t *trigger_prototypes,
1742 		const zbx_vector_ptr_t *triggers)
1743 {
1744 	const char				*__function_name = "lld_triggers_save";
1745 
1746 	int					ret = SUCCEED, i, j, new_triggers = 0, upd_triggers = 0,
1747 						new_functions = 0, new_dependencies = 0;
1748 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
1749 	zbx_lld_trigger_t			*trigger;
1750 	zbx_lld_function_t			*function;
1751 	zbx_lld_dependency_t			*dependency;
1752 	zbx_vector_ptr_t			upd_functions;	/* the ordered list of functions which will be updated */
1753 	zbx_vector_uint64_t			del_functionids, del_triggerdepids;
1754 	zbx_uint64_t				triggerid = 0, functionid = 0, triggerdepid = 0, triggerid_up;
1755 	char					*sql = NULL, *function_esc, *parameter_esc;
1756 	size_t					sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
1757 	zbx_db_insert_t				db_insert, db_insert_tdiscovery, db_insert_tfunctions, db_insert_tdepends;
1758 
1759 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1760 
1761 	zbx_vector_ptr_create(&upd_functions);
1762 	zbx_vector_uint64_create(&del_functionids);
1763 	zbx_vector_uint64_create(&del_triggerdepids);
1764 
1765 	for (i = 0; i < triggers->values_num; i++)
1766 	{
1767 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1768 
1769 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1770 			continue;
1771 
1772 		if (0 == trigger->triggerid)
1773 			new_triggers++;
1774 		else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
1775 			upd_triggers++;
1776 
1777 		for (j = 0; j < trigger->functions.values_num; j++)
1778 		{
1779 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1780 
1781 			if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
1782 			{
1783 				zbx_vector_uint64_append(&del_functionids, function->functionid);
1784 				continue;
1785 			}
1786 
1787 			if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1788 				continue;
1789 
1790 			if (0 == function->functionid)
1791 				new_functions++;
1792 			else if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1793 				zbx_vector_ptr_append(&upd_functions, function);
1794 		}
1795 
1796 		for (j = 0; j < trigger->dependencies.values_num; j++)
1797 		{
1798 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1799 
1800 			if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
1801 			{
1802 				zbx_vector_uint64_append(&del_triggerdepids, dependency->triggerdepid);
1803 				continue;
1804 			}
1805 
1806 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1807 				continue;
1808 
1809 			if (0 == dependency->triggerdepid)
1810 				new_dependencies++;
1811 		}
1812 	}
1813 
1814 	if (0 == new_triggers && 0 == new_functions && 0 == new_dependencies && 0 == upd_triggers &&
1815 			0 == upd_functions.values_num && 0 == del_functionids.values_num &&
1816 			0 == del_triggerdepids.values_num)
1817 	{
1818 		goto out;
1819 	}
1820 
1821 	DBbegin();
1822 
1823 	if (SUCCEED != DBlock_hostid(hostid))
1824 	{
1825 		/* the host was removed while processing lld rule */
1826 		DBrollback();
1827 		ret = FAIL;
1828 		goto out;
1829 	}
1830 
1831 	if (0 != new_triggers)
1832 	{
1833 		triggerid = DBget_maxid_num("triggers", new_triggers);
1834 
1835 		zbx_db_insert_prepare(&db_insert, "triggers", "triggerid", "description", "expression", "priority",
1836 				"status", "comments", "url", "type", "value", "state", "flags", NULL);
1837 
1838 		zbx_db_insert_prepare(&db_insert_tdiscovery, "trigger_discovery", "triggerid", "parent_triggerid",
1839 				NULL);
1840 	}
1841 
1842 	if (0 != new_functions)
1843 	{
1844 		functionid = DBget_maxid_num("functions", new_functions);
1845 
1846 		zbx_db_insert_prepare(&db_insert_tfunctions, "functions", "functionid", "itemid", "triggerid",
1847 				"function", "parameter", NULL);
1848 	}
1849 
1850 	if (0 != new_dependencies)
1851 	{
1852 		triggerdepid = DBget_maxid_num("trigger_depends", new_dependencies);
1853 
1854 		zbx_db_insert_prepare(&db_insert_tdepends, "trigger_depends", "triggerdepid", "triggerid_down",
1855 				"triggerid_up", NULL);
1856 	}
1857 
1858 	if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
1859 			0 != del_triggerdepids.values_num)
1860 	{
1861 		sql = zbx_malloc(sql, sql_alloc);
1862 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1863 	}
1864 
1865 	for (i = 0; i < triggers->values_num; i++)
1866 	{
1867 		char	*description_esc, *expression_esc, *comments_esc, *url_esc;
1868 		int	index;
1869 
1870 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1871 
1872 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1873 			continue;
1874 
1875 		index = zbx_vector_ptr_bsearch(trigger_prototypes, &trigger->parent_triggerid,
1876 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1877 
1878 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1879 
1880 		for (j = 0; j < trigger->functions.values_num; j++)
1881 		{
1882 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1883 
1884 			if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
1885 				continue;
1886 
1887 			if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1888 				continue;
1889 
1890 			if (0 == function->functionid)
1891 			{
1892 				zbx_db_insert_add_values(&db_insert_tfunctions, functionid, function->itemid,
1893 						(0 == trigger->triggerid ? triggerid : trigger->triggerid),
1894 						function->function, function->parameter);
1895 
1896 				function->functionid = functionid++;
1897 			}
1898 		}
1899 
1900 		if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
1901 			lld_expression_create(&trigger->expression, &trigger->functions);
1902 
1903 		if (0 == trigger->triggerid)
1904 		{
1905 			zbx_db_insert_add_values(&db_insert, triggerid, trigger->description, trigger->expression,
1906 					(int)trigger_prototype->priority, (int)trigger_prototype->status,
1907 					trigger->comments, trigger->url, (int)trigger_prototype->type,
1908 					(int)TRIGGER_VALUE_OK, (int)TRIGGER_STATE_NORMAL,
1909 					(int)ZBX_FLAG_DISCOVERY_CREATED);
1910 
1911 			zbx_db_insert_add_values(&db_insert_tdiscovery, triggerid, trigger->parent_triggerid);
1912 
1913 			trigger->triggerid = triggerid++;
1914 		}
1915 		else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
1916 		{
1917 			const char	*d = "";
1918 
1919 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set ");
1920 
1921 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION))
1922 			{
1923 				description_esc = DBdyn_escape_string(trigger->description);
1924 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "description='%s'",
1925 						description_esc);
1926 				zbx_free(description_esc);
1927 				d = ",";
1928 			}
1929 
1930 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
1931 			{
1932 				expression_esc = DBdyn_escape_string(trigger->expression);
1933 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sexpression='%s'", d,
1934 						expression_esc);
1935 				zbx_free(expression_esc);
1936 				d = ",";
1937 			}
1938 
1939 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE))
1940 			{
1941 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d,
1942 						(int)trigger_prototype->type);
1943 				d = ",";
1944 			}
1945 
1946 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY))
1947 			{
1948 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spriority=%d", d,
1949 						(int)trigger_prototype->priority);
1950 				d = ",";
1951 			}
1952 
1953 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS))
1954 			{
1955 				comments_esc = DBdyn_escape_string(trigger->comments);
1956 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scomments='%s'", d, comments_esc);
1957 				zbx_free(comments_esc);
1958 				d = ",";
1959 			}
1960 
1961 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_URL))
1962 			{
1963 				url_esc = DBdyn_escape_string(trigger->url);
1964 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl='%s'", d, url_esc);
1965 				zbx_free(url_esc);
1966 			}
1967 
1968 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1969 					" where triggerid=" ZBX_FS_UI64 ";\n", trigger->triggerid);
1970 		}
1971 	}
1972 
1973 	for (i = 0; i < triggers->values_num; i++)
1974 	{
1975 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1976 
1977 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1978 			continue;
1979 
1980 		for (j = 0; j < trigger->dependencies.values_num; j++)
1981 		{
1982 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1983 
1984 			if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
1985 				continue;
1986 
1987 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1988 				continue;
1989 
1990 			if (0 == dependency->triggerdepid)
1991 			{
1992 				triggerid_up = (NULL == dependency->trigger_up ? dependency->triggerid_up :
1993 						dependency->trigger_up->triggerid);
1994 
1995 				zbx_db_insert_add_values(&db_insert_tdepends, triggerdepid, trigger->triggerid,
1996 						triggerid_up);
1997 
1998 				dependency->triggerdepid = triggerdepid++;
1999 			}
2000 		}
2001 	}
2002 
2003 	zbx_vector_ptr_sort(&upd_functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2004 
2005 	for (i = 0; i < upd_functions.values_num; i++)
2006 	{
2007 		const char	*d = "";
2008 
2009 		function = (zbx_lld_function_t *)upd_functions.values[i];
2010 
2011 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update functions set ");
2012 
2013 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID))
2014 		{
2015 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64,
2016 					function->itemid);
2017 			d = ",";
2018 		}
2019 
2020 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION))
2021 		{
2022 			function_esc = DBdyn_escape_string(function->function);
2023 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sfunction='%s'", d,
2024 					function_esc);
2025 			zbx_free(function_esc);
2026 			d = ",";
2027 		}
2028 
2029 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER))
2030 		{
2031 			parameter_esc = DBdyn_escape_string(function->parameter);
2032 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sparameter='%s'", d,
2033 					parameter_esc);
2034 			zbx_free(parameter_esc);
2035 		}
2036 
2037 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2038 				" where functionid=" ZBX_FS_UI64 ";\n", function->functionid);
2039 	}
2040 
2041 	if (0 != del_functionids.values_num)
2042 	{
2043 		zbx_vector_uint64_sort(&del_functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2044 
2045 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where");
2046 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "functionid",
2047 				del_functionids.values, del_functionids.values_num);
2048 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2049 	}
2050 
2051 	if (0 != del_triggerdepids.values_num)
2052 	{
2053 		zbx_vector_uint64_sort(&del_triggerdepids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2054 
2055 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_depends where");
2056 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerdepid",
2057 				del_triggerdepids.values, del_triggerdepids.values_num);
2058 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2059 	}
2060 
2061 	if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2062 			0 != del_triggerdepids.values_num)
2063 	{
2064 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2065 		DBexecute("%s", sql);
2066 		zbx_free(sql);
2067 	}
2068 
2069 	if (0 != new_triggers)
2070 	{
2071 		zbx_db_insert_execute(&db_insert);
2072 		zbx_db_insert_clean(&db_insert);
2073 
2074 		zbx_db_insert_execute(&db_insert_tdiscovery);
2075 		zbx_db_insert_clean(&db_insert_tdiscovery);
2076 	}
2077 
2078 	if (0 != new_functions)
2079 	{
2080 		zbx_db_insert_execute(&db_insert_tfunctions);
2081 		zbx_db_insert_clean(&db_insert_tfunctions);
2082 	}
2083 
2084 	if (0 != new_dependencies)
2085 	{
2086 		zbx_db_insert_execute(&db_insert_tdepends);
2087 		zbx_db_insert_clean(&db_insert_tdepends);
2088 	}
2089 
2090 	DBcommit();
2091 out:
2092 	zbx_vector_uint64_destroy(&del_triggerdepids);
2093 	zbx_vector_uint64_destroy(&del_functionids);
2094 	zbx_vector_ptr_destroy(&upd_functions);
2095 
2096 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2097 
2098 	return ret;
2099 }
2100 
2101 /* hash/comparison functions to support cache/vector lookups by trigger reference */
zbx_lld_trigger_ref_hash_func(const void * data)2102 zbx_hash_t	zbx_lld_trigger_ref_hash_func(const void *data)
2103 {
2104 	zbx_hash_t			hash;
2105 	const zbx_lld_trigger_node_t	*trigger_node = (const zbx_lld_trigger_node_t *)data;
2106 	void				*ptr = NULL;
2107 
2108 	hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&trigger_node->trigger_ref.triggerid,
2109 			sizeof(trigger_node->trigger_ref.triggerid), ZBX_DEFAULT_HASH_SEED);
2110 
2111 	if (0 == trigger_node->trigger_ref.triggerid)
2112 		ptr = trigger_node->trigger_ref.trigger;
2113 
2114 	return ZBX_DEFAULT_PTR_HASH_ALGO(&ptr, sizeof(trigger_node->trigger_ref.trigger), hash);
2115 }
2116 
zbx_lld_trigger_ref_compare_func(const void * d1,const void * d2)2117 int	zbx_lld_trigger_ref_compare_func(const void *d1, const void *d2)
2118 {
2119 	const zbx_lld_trigger_node_t	*n1 = (const zbx_lld_trigger_node_t *)d1;
2120 	const zbx_lld_trigger_node_t	*n2 = (const zbx_lld_trigger_node_t *)d2;
2121 
2122 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2123 
2124 	/* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2125 	if (0 != n1->trigger_ref.triggerid)
2126 		return 0;
2127 
2128 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2129 
2130 	return 0;
2131 }
2132 
2133 /* comparison function to determine trigger dependency validation order */
zbx_lld_trigger_node_compare_func(const void * d1,const void * d2)2134 int	zbx_lld_trigger_node_compare_func(const void *d1, const void *d2)
2135 {
2136 	const zbx_lld_trigger_node_t	*n1 = *(const zbx_lld_trigger_node_t **)d1;
2137 	const zbx_lld_trigger_node_t	*n2 = *(const zbx_lld_trigger_node_t **)d2;
2138 
2139 	/* sort in ascending order, but ensure that existing triggers are first */
2140 	if (0 != n1->trigger_ref.triggerid && 0 == n2->trigger_ref.triggerid)
2141 		return -1;
2142 
2143 	/* give priority to nodes with less parents */
2144 	ZBX_RETURN_IF_NOT_EQUAL(n1->parents, n2->parents);
2145 
2146 	/* compare ids */
2147 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2148 
2149 	/* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2150 	if (0 != n1->trigger_ref.triggerid)
2151 		return 0;
2152 
2153 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2154 
2155 	return 0;
2156 }
2157 
2158 /******************************************************************************
2159  *                                                                            *
2160  * Function: lld_trigger_cache_append                                         *
2161  *                                                                            *
2162  * Purpose: adds a node to trigger cache                                      *
2163  *                                                                            *
2164  * Parameters: cache     - [IN] the trigger cache                             *
2165  *             triggerid - [IN] the trigger id                                *
2166  *             trigger   - [IN] the trigger data for new triggers             *
2167  *                                                                            *
2168  * Return value: the added node                                               *
2169  *                                                                            *
2170  ******************************************************************************/
lld_trigger_cache_append(zbx_hashset_t * cache,zbx_uint64_t triggerid,zbx_lld_trigger_t * trigger)2171 static zbx_lld_trigger_node_t	*lld_trigger_cache_append(zbx_hashset_t *cache, zbx_uint64_t triggerid,
2172 		zbx_lld_trigger_t *trigger)
2173 {
2174 	zbx_lld_trigger_node_t	node_local;
2175 
2176 	node_local.trigger_ref.triggerid = triggerid;
2177 	node_local.trigger_ref.trigger = trigger;
2178 	node_local.trigger_ref.flags = 0;
2179 	node_local.iter_num = 0;
2180 	node_local.parents = 0;
2181 
2182 	zbx_vector_ptr_create(&node_local.dependencies);
2183 
2184 	return zbx_hashset_insert(cache, &node_local, sizeof(node_local));
2185 }
2186 
2187 /******************************************************************************
2188  *                                                                            *
2189  * Function: lld_trigger_cache_add_trigger_node                               *
2190  *                                                                            *
2191  * Purpose: add trigger and all triggers related to it to trigger dependency  *
2192  *          validation cache.                                                 *
2193  *                                                                            *
2194  * Parameters: cache           - [IN] the trigger cache                       *
2195  *             trigger         - [IN] the trigger to add                      *
2196  *             triggerids_up   - [OUT] identifiers of generic trigger         *
2197  *                                     dependents                             *
2198  *             triggerids_down - [OUT] identifiers of generic trigger         *
2199  *                                     dependencies                           *
2200  *                                                                            *
2201  ******************************************************************************/
lld_trigger_cache_add_trigger_node(zbx_hashset_t * cache,zbx_lld_trigger_t * trigger,zbx_vector_uint64_t * triggerids_up,zbx_vector_uint64_t * triggerids_down)2202 static void	lld_trigger_cache_add_trigger_node(zbx_hashset_t *cache, zbx_lld_trigger_t *trigger,
2203 		zbx_vector_uint64_t *triggerids_up, zbx_vector_uint64_t *triggerids_down)
2204 {
2205 	zbx_lld_trigger_ref_t	*trigger_ref;
2206 	zbx_lld_trigger_node_t	*trigger_node, trigger_node_local;
2207 	zbx_lld_dependency_t	*dependency;
2208 	int			i;
2209 
2210 	trigger_node_local.trigger_ref.triggerid = trigger->triggerid;
2211 	trigger_node_local.trigger_ref.trigger = trigger;
2212 
2213 	if (NULL != (trigger_node = zbx_hashset_search(cache, &trigger_node_local)))
2214 		return;
2215 
2216 	trigger_node = lld_trigger_cache_append(cache, trigger->triggerid, trigger);
2217 
2218 	for (i = 0; i < trigger->dependencies.values_num; i++)
2219 	{
2220 		dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2221 
2222 		if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2223 			continue;
2224 
2225 		trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_ref_t));
2226 
2227 		trigger_ref->triggerid = dependency->triggerid_up;
2228 		trigger_ref->trigger = dependency->trigger_up;
2229 		trigger_ref->flags = (0 == dependency->triggerdepid ? ZBX_LLD_TRIGGER_DEPENDENCY_NEW :
2230 				ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL);
2231 
2232 		zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
2233 
2234 		if (NULL == trigger_ref->trigger)
2235 		{
2236 			trigger_node_local.trigger_ref.triggerid = trigger_ref->triggerid;
2237 			trigger_node_local.trigger_ref.trigger = NULL;
2238 
2239 			if (NULL == zbx_hashset_search(cache, &trigger_node_local))
2240 			{
2241 				zbx_vector_uint64_append(triggerids_up, trigger_ref->triggerid);
2242 				zbx_vector_uint64_append(triggerids_down, trigger_ref->triggerid);
2243 
2244 				lld_trigger_cache_append(cache, trigger_ref->triggerid, NULL);
2245 			}
2246 		}
2247 	}
2248 
2249 	if (0 != trigger->triggerid)
2250 		zbx_vector_uint64_append(triggerids_up, trigger->triggerid);
2251 
2252 	for (i = 0; i < trigger->dependents.values_num; i++)
2253 	{
2254 		lld_trigger_cache_add_trigger_node(cache, trigger->dependents.values[i], triggerids_up,
2255 				triggerids_down);
2256 	}
2257 
2258 	for (i = 0; i < trigger->dependencies.values_num; i++)
2259 	{
2260 		dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2261 
2262 		if (NULL != dependency->trigger_up)
2263 		{
2264 			lld_trigger_cache_add_trigger_node(cache, dependency->trigger_up, triggerids_up,
2265 					triggerids_down);
2266 		}
2267 	}
2268 }
2269 
2270 /******************************************************************************
2271  *                                                                            *
2272  * Function: lld_trigger_cache_init                                           *
2273  *                                                                            *
2274  * Purpose: initializes trigger cache used to perform trigger dependency      *
2275  *          validation                                                        *
2276  *                                                                            *
2277  * Parameters: cache    - [IN] the trigger cache                              *
2278  *             triggers - [IN] the discovered triggers                        *
2279  *                                                                            *
2280  * Comments: Triggers with new dependencies and.all triggers related to them  *
2281  *           are added to cache.                                              *
2282  *                                                                            *
2283  ******************************************************************************/
lld_trigger_cache_init(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers)2284 static void	lld_trigger_cache_init(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers)
2285 {
2286 	const char		*__function_name = "lld_trigger_cache_init";
2287 
2288 	zbx_vector_uint64_t	triggerids_up, triggerids_down;
2289 	int			i, j;
2290 	char			*sql = NULL;
2291 	size_t			sql_alloc = 0, sql_offset;
2292 	DB_RESULT		result;
2293 	DB_ROW			row;
2294 	zbx_lld_trigger_ref_t	*trigger_ref;
2295 	zbx_lld_trigger_node_t	*trigger_node, trigger_node_local;
2296 
2297 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2298 
2299 	zbx_hashset_create(cache, triggers->values_num, zbx_lld_trigger_ref_hash_func,
2300 			zbx_lld_trigger_ref_compare_func);
2301 
2302 	zbx_vector_uint64_create(&triggerids_down);
2303 	zbx_vector_uint64_create(&triggerids_up);
2304 
2305 	/* add all triggers with new dependencies to trigger cache */
2306 	for (i = 0; i < triggers->values_num; i++)
2307 	{
2308 		zbx_lld_trigger_t	*trigger = (zbx_lld_trigger_t *)triggers->values[i];
2309 
2310 		for (j = 0; j < trigger->dependencies.values_num; j++)
2311 		{
2312 			zbx_lld_dependency_t	*dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2313 
2314 			if (0 == dependency->triggerdepid)
2315 				break;
2316 		}
2317 
2318 		if (j != trigger->dependencies.values_num)
2319 			lld_trigger_cache_add_trigger_node(cache, trigger, &triggerids_up, &triggerids_down);
2320 	}
2321 
2322 	/* keep trying to load generic dependents/dependencies until there are nothing to load */
2323 	while (0 != triggerids_up.values_num || 0 != triggerids_down.values_num)
2324 	{
2325 		/* load dependents */
2326 		if (0 != triggerids_down.values_num)
2327 		{
2328 			sql_offset = 0;
2329 			zbx_vector_uint64_sort(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2330 			zbx_vector_uint64_uniq(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2331 
2332 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2333 					"select td.triggerid_down,td.triggerid_up"
2334 					" from trigger_depends td"
2335 						" left join triggers t"
2336 							" on td.triggerid_up=t.triggerid"
2337 					" where t.flags<>%d"
2338 						" and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
2339 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_down",
2340 					triggerids_down.values, triggerids_down.values_num);
2341 
2342 			zbx_vector_uint64_clear(&triggerids_down);
2343 
2344 			result = DBselect("%s", sql);
2345 
2346 			while (NULL != (row = DBfetch(result)))
2347 			{
2348 				int			new_node = 0;
2349 				zbx_lld_trigger_node_t	*trigger_node_up;
2350 
2351 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[1]);
2352 
2353 				if (NULL == (trigger_node_up = zbx_hashset_search(cache, &trigger_node_local)))
2354 				{
2355 					trigger_node_up = lld_trigger_cache_append(cache,
2356 							trigger_node_local.trigger_ref.triggerid, NULL);
2357 					new_node = 1;
2358 				}
2359 
2360 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
2361 
2362 				if (NULL == (trigger_node = zbx_hashset_search(cache, &trigger_node_local)))
2363 				{
2364 					THIS_SHOULD_NEVER_HAPPEN;
2365 					continue;
2366 				}
2367 
2368 				/* check if the dependency is not already registered in cache */
2369 				for (i = 0; i < trigger_node->dependencies.values_num; i++)
2370 				{
2371 					trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
2372 
2373 					/* references to generic triggers will always have valid id value */
2374 					if (trigger_ref->triggerid == trigger_node_up->trigger_ref.triggerid)
2375 						break;
2376 				}
2377 
2378 				/* if the dependency was not found - add it */
2379 				if (i == trigger_node->dependencies.values_num)
2380 				{
2381 					trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL,
2382 							sizeof(zbx_lld_trigger_ref_t));
2383 
2384 					trigger_ref->triggerid = trigger_node_up->trigger_ref.triggerid;
2385 					trigger_ref->trigger = NULL;
2386 					trigger_ref->flags = ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL;
2387 
2388 					zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
2389 
2390 					trigger_node_up->parents++;
2391 				}
2392 
2393 				if (1 == new_node)
2394 				{
2395 					/* if the trigger was added to cache, we must check its dependencies */
2396 					zbx_vector_uint64_append(&triggerids_up,
2397 							trigger_node_up->trigger_ref.triggerid);
2398 					zbx_vector_uint64_append(&triggerids_down,
2399 							trigger_node_up->trigger_ref.triggerid);
2400 				}
2401 			}
2402 
2403 			DBfree_result(result);
2404 		}
2405 
2406 		/* load dependencies */
2407 		if (0 != triggerids_up.values_num)
2408 		{
2409 			sql_offset = 0;
2410 			zbx_vector_uint64_sort(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2411 			zbx_vector_uint64_uniq(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2412 
2413 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2414 					"select td.triggerid_down"
2415 					" from trigger_depends td"
2416 						" left join triggers t"
2417 							" on t.triggerid=td.triggerid_down"
2418 					" where t.flags<>%d"
2419 						" and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
2420 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_up", triggerids_up.values,
2421 					triggerids_up.values_num);
2422 
2423 			zbx_vector_uint64_clear(&triggerids_up);
2424 
2425 			result = DBselect("%s", sql);
2426 
2427 			while (NULL != (row = DBfetch(result)))
2428 			{
2429 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
2430 
2431 				if (NULL != zbx_hashset_search(cache, &trigger_node_local))
2432 					continue;
2433 
2434 				trigger_node = lld_trigger_cache_append(cache, trigger_node_local.trigger_ref.triggerid,
2435 						NULL);
2436 
2437 				zbx_vector_uint64_append(&triggerids_up, trigger_node_local.trigger_ref.triggerid);
2438 				zbx_vector_uint64_append(&triggerids_down, trigger_node_local.trigger_ref.triggerid);
2439 			}
2440 
2441 			DBfree_result(result);
2442 		}
2443 
2444 	}
2445 
2446 	zbx_free(sql);
2447 
2448 	zbx_vector_uint64_destroy(&triggerids_up);
2449 	zbx_vector_uint64_destroy(&triggerids_down);
2450 
2451 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2452 }
2453 
2454 /******************************************************************************
2455  *                                                                            *
2456  * Function: zbx_trigger_cache_clean                                          *
2457  *                                                                            *
2458  * Purpose: releases resources allocated by trigger cache                     *
2459  *          validation                                                        *
2460  *                                                                            *
2461  * Parameters: cache - [IN] the trigger cache                                 *
2462  *                                                                            *
2463  ******************************************************************************/
zbx_trigger_cache_clean(zbx_hashset_t * cache)2464 static void	zbx_trigger_cache_clean(zbx_hashset_t *cache)
2465 {
2466 	zbx_hashset_iter_t	iter;
2467 	zbx_lld_trigger_node_t	*trigger_node;
2468 
2469 	zbx_hashset_iter_reset(cache, &iter);
2470 	while (NULL != (trigger_node = zbx_hashset_iter_next(&iter)))
2471 	{
2472 		zbx_vector_ptr_clear_ext(&trigger_node->dependencies, zbx_ptr_free);
2473 		zbx_vector_ptr_destroy(&trigger_node->dependencies);
2474 	}
2475 
2476 	zbx_hashset_destroy(cache);
2477 }
2478 
2479 /******************************************************************************
2480  *                                                                            *
2481  * Function: lld_trigger_dependency_delete                                    *
2482  *                                                                            *
2483  * Purpose: removes trigger dependency                                        *
2484  *                                                                            *
2485  * Parameters: from  - [IN] the reference to dependent trigger                *
2486  *             to    - [IN] the reference to trigger the from depends on      *
2487  *             error - [OUT] the error message                                *
2488  *                                                                            *
2489  * Comments: If possible (the dependency loop was introduced by discovered    *
2490  *           dependencies) the last dependency in the loop will be removed.   *
2491  *           Otherwise (the triggers in database already had dependency loop) *
2492  *           the last dependency in the loop will be marked as removed,       *
2493  *           however the dependency in database will be left intact.          *
2494  *                                                                            *
2495  ******************************************************************************/
lld_trigger_dependency_delete(zbx_lld_trigger_ref_t * from,zbx_lld_trigger_ref_t * to,char ** error)2496 static void	lld_trigger_dependency_delete(zbx_lld_trigger_ref_t *from, zbx_lld_trigger_ref_t *to, char **error)
2497 {
2498 	zbx_lld_trigger_t	*trigger;
2499 	int			i;
2500 	char			*trigger_desc;
2501 
2502 	if (ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == to->flags)
2503 	{
2504 		/* When old dependency loop has been detected mark it as deleted to avoid   */
2505 		/* infinite recursion during dependency validation, but don't really delete */
2506 		/* it because only new dependencies can be deleted.                         */
2507 
2508 		/* in old dependency loop there are no new triggers, so all involved */
2509 		/* triggers have valid identifiers                                   */
2510 		zabbix_log(LOG_LEVEL_CRIT, "existing recursive dependency loop detected for trigger \""
2511 				ZBX_FS_UI64 "\"", to->triggerid);
2512 		return;
2513 	}
2514 
2515 	trigger = from->trigger;
2516 
2517 	/* remove the dependency */
2518 	for (i = 0; i < trigger->dependencies.values_num; i++)
2519 	{
2520 		zbx_lld_dependency_t	*dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
2521 
2522 		if ((NULL != dependency->trigger_up && dependency->trigger_up == to->trigger) ||
2523 				(0 != dependency->triggerid_up && dependency->triggerid_up == to->triggerid))
2524 		{
2525 			zbx_free(dependency);
2526 			zbx_vector_ptr_remove(&trigger->dependencies, i);
2527 
2528 			break;
2529 		}
2530 	}
2531 
2532 	if (0 != from->triggerid)
2533 		trigger_desc = zbx_dsprintf(NULL, ZBX_FS_UI64, from->triggerid);
2534 	else
2535 		trigger_desc = zbx_strdup(NULL, from->trigger->description);
2536 
2537 	*error = zbx_strdcatf(*error, "Cannot create all trigger \"%s\" dependencies:"
2538 			" recursion too deep.\n", trigger_desc);
2539 
2540 	zbx_free(trigger_desc);
2541 }
2542 
2543 /******************************************************************************
2544  *                                                                            *
2545  * Function: lld_trigger_dependencies_iter                                    *
2546  *                                                                            *
2547  * Purpose: iterates through trigger dependencies to find dependency loops    *
2548  *                                                                            *
2549  * Parameters: cache         - [IN] the trigger cache                         *
2550  *             triggers      - [IN] the discovered triggers                   *
2551  *             trigger_node  - [IN] the trigger to check                      *
2552  *             iter          - [IN] the dependency iterator                   *
2553  *             level         - [IN] the dependency level                      *
2554  *             error         - [OUT] the error message                        *
2555  *                                                                            *
2556  * Return value: SUCCEED - the trigger's dependency chain in valid            *
2557  *               FAIL    - a dependency loop was detected                     *
2558  *                                                                            *
2559  * Comments: If the validation fails the offending dependency is removed.     *
2560  *                                                                            *
2561  ******************************************************************************/
lld_trigger_dependencies_iter(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers,zbx_lld_trigger_node_t * trigger_node,zbx_lld_trigger_node_iter_t * iter,int level,char ** error)2562 static int	lld_trigger_dependencies_iter(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers,
2563 		zbx_lld_trigger_node_t *trigger_node, zbx_lld_trigger_node_iter_t *iter, int level, char **error)
2564 {
2565 	int				i;
2566 	zbx_lld_trigger_ref_t		*trigger_ref;
2567 	zbx_lld_trigger_node_t		*trigger_node_up;
2568 	zbx_lld_trigger_node_iter_t	child_iter, *piter;
2569 
2570 	if (trigger_node->iter_num == iter->iter_num || ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
2571 	{
2572 		/* dependency loop detected, resolve it by deleting corresponding dependency */
2573 		lld_trigger_dependency_delete(iter->ref_from, iter->ref_to, error);
2574 
2575 		/* mark the dependency as removed */
2576 		iter->ref_to->flags = ZBX_LLD_TRIGGER_DEPENDENCY_DELETE;
2577 
2578 		return FAIL;
2579 	}
2580 
2581 	trigger_node->iter_num = iter->iter_num;
2582 
2583 	for (i = 0; i < trigger_node->dependencies.values_num; i++)
2584 	{
2585 		trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
2586 
2587 		/* skip dependencies marked as deleted */
2588 		if (ZBX_LLD_TRIGGER_DEPENDENCY_DELETE == trigger_ref->flags)
2589 			continue;
2590 
2591 		if (NULL == (trigger_node_up = zbx_hashset_search(cache, trigger_ref)))
2592 		{
2593 			THIS_SHOULD_NEVER_HAPPEN;
2594 			continue;
2595 		}
2596 
2597 		/* Remember last dependency that could be cut.                         */
2598 		/* It should be either a last new dependency or just a last dependency */
2599 		/* if no new dependencies were encountered.                            */
2600 		if (ZBX_LLD_TRIGGER_DEPENDENCY_NEW == trigger_ref->flags || NULL == iter->ref_to ||
2601 				ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == iter->ref_to->flags)
2602 		{
2603 			child_iter.ref_from = &trigger_node->trigger_ref;
2604 			child_iter.ref_to = trigger_ref;
2605 			child_iter.iter_num = iter->iter_num;
2606 
2607 			piter = &child_iter;
2608 		}
2609 		else
2610 			piter = iter;
2611 
2612 		if (FAIL == lld_trigger_dependencies_iter(cache, triggers, trigger_node_up, piter, level + 1, error))
2613 			return FAIL;
2614 	}
2615 
2616 	trigger_node->iter_num = 0;
2617 
2618 	return SUCCEED;
2619 }
2620 
2621 /******************************************************************************
2622  *                                                                            *
2623  * Function: lld_trigger_dependencies_validate                                *
2624  *                                                                            *
2625  * Purpose: validate discovered trigger dependencies                          *
2626  *                                                                            *
2627  * Parameters: triggers - [IN] the discovered triggers                        *
2628  *             error    - [OUT] the error message                             *
2629  *             triggers - [IN] the discovered triggers                        *
2630  *             trigger  - [IN] the trigger to check                           *
2631  *             iter     - [IN] the dependency iterator                        *
2632  *             level    - [IN] the dependency level                           *
2633  *                                                                            *
2634  * Comments: During validation the dependency loops will be resolved by       *
2635  *           removing offending dependencies.                                 *
2636  *                                                                            *
2637  ******************************************************************************/
lld_trigger_dependencies_validate(zbx_vector_ptr_t * triggers,char ** error)2638 static void	lld_trigger_dependencies_validate(zbx_vector_ptr_t *triggers, char **error)
2639 {
2640 	const char			*__function_name = "lld_trigger_dependencies_validate";
2641 
2642 	zbx_hashset_t			cache;
2643 	zbx_hashset_iter_t		iter;
2644 	zbx_lld_trigger_node_t		*trigger_node, *trigger_node_up;
2645 	zbx_lld_trigger_node_iter_t	node_iter = {0};
2646 	zbx_vector_ptr_t		nodes;
2647 	int				i;
2648 
2649 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2650 
2651 	lld_trigger_cache_init(&cache, triggers);
2652 
2653 	/* Perform dependency validation in the order of trigger ids and starting with parentless triggers. */
2654 	/* This will give some consistency in choosing what dependencies should be deleted in the case of   */
2655 	/* recursion.                                                                                       */
2656 	zbx_vector_ptr_create(&nodes);
2657 	zbx_vector_ptr_reserve(&nodes, cache.num_data);
2658 
2659 	zbx_hashset_iter_reset(&cache, &iter);
2660 	while (NULL != (trigger_node = zbx_hashset_iter_next(&iter)))
2661 	{
2662 		for (i = 0; i < trigger_node->dependencies.values_num; i++)
2663 		{
2664 			if (NULL == (trigger_node_up = zbx_hashset_search(&cache,
2665 					trigger_node->dependencies.values[i])))
2666 			{
2667 				THIS_SHOULD_NEVER_HAPPEN;
2668 				continue;
2669 			}
2670 
2671 			trigger_node_up->parents++;
2672 		}
2673 		zbx_vector_ptr_append(&nodes, trigger_node);
2674 	}
2675 
2676 	zbx_vector_ptr_sort(&nodes, zbx_lld_trigger_node_compare_func);
2677 
2678 	for (i = 0; i < nodes.values_num; i++)
2679 	{
2680 		if (NULL == (trigger_node = zbx_hashset_search(&cache, (zbx_lld_trigger_node_t *)nodes.values[i])))
2681 		{
2682 			THIS_SHOULD_NEVER_HAPPEN;
2683 			continue;
2684 		}
2685 
2686 		/* If dependency iterator returns false it means that dependency loop was detected */
2687 		/* (and resolved). In this case we have to validate dependencies for this trigger  */
2688 		/* again.                                                                          */
2689 		do
2690 		{
2691 			node_iter.iter_num++;
2692 			node_iter.ref_from = NULL;
2693 			node_iter.ref_to = NULL;
2694 		}
2695 		while (SUCCEED != lld_trigger_dependencies_iter(&cache, triggers, trigger_node, &node_iter, 0, error));
2696 	}
2697 
2698 	zbx_vector_ptr_destroy(&nodes);
2699 	zbx_trigger_cache_clean(&cache);
2700 
2701 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2702 }
2703 
2704 /******************************************************************************
2705  *                                                                            *
2706  * Function: lld_update_triggers                                              *
2707  *                                                                            *
2708  * Purpose: add or update triggers for discovered items                       *
2709  *                                                                            *
2710  * Return value: SUCCEED - if triggers were successfully added/updated or     *
2711  *                         adding/updating was not necessary                  *
2712  *               FAIL    - triggers cannot be added/updated                   *
2713  *                                                                            *
2714  ******************************************************************************/
lld_update_triggers(zbx_uint64_t hostid,zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,char ** error)2715 int	lld_update_triggers(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows, char **error)
2716 {
2717 	const char			*__function_name = "lld_update_triggers";
2718 
2719 	zbx_vector_ptr_t		trigger_prototypes;
2720 	zbx_vector_ptr_t		triggers;
2721 	zbx_vector_ptr_t		items;
2722 	zbx_lld_trigger_t		*trigger;
2723 	zbx_lld_trigger_prototype_t	*trigger_prototype;
2724 	int				ret = SUCCEED, i;
2725 
2726 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2727 
2728 	zbx_vector_ptr_create(&trigger_prototypes);
2729 
2730 	lld_trigger_prototypes_get(lld_ruleid, &trigger_prototypes);
2731 
2732 	if (0 == trigger_prototypes.values_num)
2733 		goto out;
2734 
2735 	zbx_vector_ptr_create(&triggers);	/* list of triggers which were created or will be created or */
2736 						/* updated by the trigger prototype */
2737 	zbx_vector_ptr_create(&items);		/* list of items which are related to the trigger prototypes */
2738 
2739 	lld_triggers_get(&trigger_prototypes, &triggers);
2740 	lld_functions_get(&trigger_prototypes, &triggers);
2741 	lld_dependencies_get(&trigger_prototypes, &triggers);
2742 	lld_items_get(&trigger_prototypes, &items);
2743 
2744 	/* simplifying trigger expressions */
2745 
2746 	for (i = 0; i < trigger_prototypes.values_num; i++)
2747 	{
2748 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes.values[i];
2749 
2750 		lld_expression_simplify(&trigger_prototype->expression, &trigger_prototype->functions);
2751 	}
2752 
2753 	for (i = 0; i < triggers.values_num; i++)
2754 	{
2755 		trigger = (zbx_lld_trigger_t *)triggers.values[i];
2756 
2757 		lld_expression_simplify(&trigger->expression, &trigger->functions);
2758 	}
2759 
2760 	/* making triggers */
2761 
2762 	lld_triggers_make(&trigger_prototypes, &triggers, &items, lld_rows, error);
2763 	lld_triggers_validate(hostid, &triggers, error);
2764 	lld_trigger_dependencies_make(&trigger_prototypes, &triggers, &items, lld_rows, error);
2765 	lld_trigger_dependencies_validate(&triggers, error);
2766 	ret = lld_triggers_save(hostid, &trigger_prototypes, &triggers);
2767 
2768 	/* cleaning */
2769 
2770 	zbx_vector_ptr_clear_ext(&items, (zbx_mem_free_func_t)lld_item_free);
2771 	zbx_vector_ptr_clear_ext(&triggers, (zbx_mem_free_func_t)lld_trigger_free);
2772 	zbx_vector_ptr_destroy(&items);
2773 	zbx_vector_ptr_destroy(&triggers);
2774 out:
2775 	zbx_vector_ptr_clear_ext(&trigger_prototypes, (zbx_mem_free_func_t)lld_trigger_prototype_free);
2776 	zbx_vector_ptr_destroy(&trigger_prototypes);
2777 
2778 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2779 
2780 	return ret;
2781 }
2782