zabbix-agent2/src/libs/zbxdbcache/dbconfig.c
/******************************************************************************
 *                                                                            *
 * Function: DCconfig_lock_triggers_by_history_items                          *
 *                                                                            *
 * Purpose: Lock triggers for specified items so that multiple processes do   *
 *          not process one trigger simultaneously. Otherwise, this leads to  *
 *          problems like multiple successive OK events or escalations being  *
 *          started and not cancelled, because they are not seen in parallel  *
 *          transactions.                                                     *
 *                                                                            *
 * Parameters: history_items - [IN/OUT] list of history items history syncer  *
 *                                    wishes to take for processing; on       *
 *                                    output, the item locked field is set    *
 *                                    to 0 if the corresponding item cannot   *
 *                                    be taken                                *
 *             triggerids  - [OUT] list of trigger IDs that this function has *
 *                                 locked for processing; unlock those using  *
 *                                 DCconfig_unlock_triggers() function        *
 *                                                                            *
 * Author: Aleksandrs Saveljevs                                               *
 *                                                                            *
 * Comments: This does not solve the problem fully (e.g., ZBX-7484). There is *
 *           a significant time period between the place where we lock the    *
 *           triggers and the place where we process them. So it could happen *
 *           that a configuration cache update happens after we have locked   *
 *           the triggers and it turns out that in the updated configuration  *
 *           there is a new trigger for two of the items that two different   *
 *           history syncers have taken for processing. In that situation,    *
 *           the problem we are solving here might still happen. However,     *
 *           locking triggers makes this problem much less likely and only in *
 *           case configuration changes. On a stable configuration, it should *
 *           work without any problems.                                       *
 *                                                                            *
 * Return value: the number of items available for processing (unlocked).     *
 *                                                                            *
 ******************************************************************************/
DCconfig_lock_triggers_by_history_items

Purpose: Lock triggers for specified items so that multiple processes do
not process one trigger simultaneously. Otherwise, this leads to
problems like multiple successive OK events or escalations being
started and not cancelled, because they are not seen in parallel
transactions.

Parameters: history_items - [IN/OUT] list of history items history syncer
wishes to take for processing; on
output, the item locked field is set
to 0 if the corresponding item cannot
be taken
triggerids  - [OUT] list of trigger IDs that this function has
locked for processing; unlock those using
DCconfig_unlock_triggers() function

Author: Aleksandrs Saveljevs

Comments: This does not solve the problem fully . There is
a significant time period between the place where we lock the
triggers and the place where we process them. So it could happen
that a configuration cache update happens after we have locked
the triggers and it turns out that in the updated configuration
there is a new trigger for two of the items that two different
history syncers have taken for processing. In that situation,
the problem we are solving here might still happen. However,
locking triggers makes this problem much less likely and only in
case configuration changes. On a stable configuration, it should
work without any problems.

Return value: the number of items available for processing (unlocked).
DCconfig_lock_triggers_by_history_items Purpose : Lock triggers for specified items so that multiple processes do not process one trigger simultaneously . Otherwise this leads to problems like multiple successive OK events or escalations being started and not cancelled because they are not seen in parallel transactions . Parameters : history_items - [ IN / OUT ] list of history items history syncer wishes to take for processing ; on output the item locked field is set to 0 if the corresponding item cannot be taken triggerids - [ OUT ] list of trigger IDs that this function has locked for processing ; unlock those using DCconfig_unlock_triggers () function Author : Aleksandrs Saveljevs Comments : This does not solve the problem fully . There is a significant time period between the place where we lock the triggers and the place where we process them . So it could happen that a configuration cache update happens after we have locked the triggers and it turns out that in the updated configuration there is a new trigger for two of the items that two different history syncers have taken for processing . In that situation the problem we are solving here might still happen . However locking triggers makes this problem much less likely and only in case configuration changes . On a stable configuration it should work without any problems . Return value : the number of items available for processing ( unlocked ) .
int	DCconfig_lock_triggers_by_history_items(zbx_vector_ptr_t *history_items, zbx_vector_uint64_t *triggerids)
{
	int			i, j, locked_num = 0;
	const ZBX_DC_ITEM	*dc_item;
	ZBX_DC_TRIGGER		*dc_trigger;
	zbx_hc_item_t		*history_item;
	WRLOCK_CACHE;
	for (i = 0; i < history_items->values_num; i++)
	{
		history_item = (zbx_hc_item_t *)history_items->values[i];
		if (0 != (ZBX_DC_FLAG_NOVALUE & history_item->tail->flags))
			continue;
		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &history_item->itemid)))
			continue;
		if (NULL == dc_item->triggers)
			continue;
		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
		{
			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
				continue;
			if (1 == dc_trigger->locked)
			{
				locked_num++;
				history_item->status = ZBX_HC_ITEM_STATUS_BUSY;
				goto next;
			}
		}
		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
		{
			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
				continue;
			dc_trigger->locked = 1;
			zbx_vector_uint64_append(triggerids, dc_trigger->triggerid);
		}
next:;
	}
	UNLOCK_CACHE;
	return history_items->values_num - locked_num;
}
int DCconfig_lock_triggers_by_history_items ( zbx_vector_ptr_t * history_items , zbx_vector_uint64_t * triggerids ) { int i , j , locked_num = 0 ; const ZBX_DC_ITEM * dc_item ; ZBX_DC_TRIGGER * dc_trigger ; zbx_hc_item_t * history_item ; WRLOCK_CACHE ; for ( i = 0 ; i < history_items -> values_num ; i ++ ) { history_item = ( zbx_hc_item_t * ) history_items -> values [ i ] ; if ( 0 != ( ZBX_DC_FLAG_NOVALUE & history_item -> tail -> flags ) ) continue ; if ( NULL == ( dc_item = ( ZBX_DC_ITEM * ) zbx_hashset_search ( & config -> items , & history_item -> itemid ) ) ) continue ; if ( NULL == dc_item -> triggers ) continue ; for ( j = 0 ; NULL != ( dc_trigger = dc_item -> triggers [ j ] ) ; j ++ ) { if ( TRIGGER_STATUS_ENABLED != dc_trigger -> status ) continue ; if ( 1 == dc_trigger -> locked ) { locked_num ++ ; history_item -> status = ZBX_HC_ITEM_STATUS_BUSY ; goto next ; } } for ( j = 0 ; NULL != ( dc_trigger = dc_item -> triggers [ j ] ) ; j ++ ) { if ( TRIGGER_STATUS_ENABLED != dc_trigger -> status ) continue ; dc_trigger -> locked = 1 ; zbx_vector_uint64_append ( triggerids , dc_trigger -> triggerid ) ; } next : ; } UNLOCK_CACHE ; return history_items -> values_num - locked_num ; }
Function: DCconfig_lock_triggers_by_history_items                          
                                                                            
 Purpose: Lock triggers for specified items so that multiple processes do   
          not process one trigger simultaneously.
Function : DCconfig_lock_triggers_by_history_items Purpose : Lock triggers for specified items so that multiple processes do not process one trigger simultaneously .