>From 34d71eb4a947051cc0a1251745b8829245cd2e7d Mon Sep 17 00:00:00 2001
From: Michael Friedrich <michael.friedrich@univie.ac.at>
Date: Tue, 1 Nov 2011 13:35:20 +0100
Subject: [PATCH] reduce notification load; fix $NOTIFICATIONRECIPIENTS$ macro
 #98

1) currently, the list of contacts to be notified is created
and finally on the notification actually happening, the
viability checks happen. this will cause heavy load on systems
with many contacts configured, looping even for the contacts
who won't pass the notification viability tests.
in order to solve that, a patch by Opsview Team was taken into
account, moving the viability checks directly into the notification
list creation before adding a contact to the list.

note: the check against the timeperiod will happen on list creation,
not an actual notification being sent. but that's a minor flaw.

2) while moving the viability checks on list creation, this will
cause that not *all* contacts of the host/service will be added to
the list, but just those actually receiving the notification. the
macro $NOTIFICATIONSRECEIPIENTS$ gets populated in add_notification()
and will therefore hold only those contacts being viable for a
notification.

note: this fixes #98 on the bug tracker.

for further analysis and tests, please refer over here
https://dev.icinga.org/issues/1744
https://dev.icinga.org/issues/2023

kudos to Opsview Team for their initial patch, this has been
reworked into current macro threadsafety logic with some proper
inline comments.
---
 Changelog            |   11 +++++
 base/notifications.c |  106 +++++++++++++++++++++++++++++++++++++-------------
 include/nagios.h     |    4 +-
 3 files changed, 92 insertions(+), 29 deletions(-)

diff --git a/Changelog b/Changelog
index 0a5e9e6..8742ca8 100644
--- a/Changelog
+++ b/Changelog
@@ -2,6 +2,17 @@
 Nagios 3.x Change Log
 #####################
 
+3.x.x - ??/??/????
+
+ENHANCEMENTS
+* reduce notification load by moving notification viability check into notification list creation (Opsview Team)
+
+FIXES
+* fix $NOTIFICATIONRECIPIENTS$ macro contains all contacts assigned to host|service, not only notified contacts (Icinga Development Team) #98
+
+WARNINGS
+
+
 3.3.1 - 07/25/2011
 ------------------
 ENHANCEMENTS
diff --git a/base/notifications.c b/base/notifications.c
index 6f5a5ab..1dbd849 100644
--- a/base/notifications.c
+++ b/base/notifications.c
@@ -108,9 +108,26 @@ int service_notification(service *svc, int type, char *not_author, char *not_dat
 
 	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Creating list of contacts to be notified.\n");
 
-	/* create the contact notification list for this service */
+	/* allocate memory for macros */
 	memset(&mac, 0, sizeof(mac));
-	create_notification_list_from_service(&mac, svc, options, &escalated);
+
+	/* create the contact notification list for this service */
+
+	/* 2011-11-01 MF:  
+	   check viability before adding a contact
+	   to the notification list, requires type
+	   this prevents us from running through all
+	   the steps until notify_contact_of_host|service
+	   is reached. furthermore the $NOTIFICATIONRECIPIENTS$
+	   macro only gets populated with actual recipients,
+	   not all contacts assigned to that host|service.
+
+	   note: checks against timeperiod will happen now(),
+	   and not when the notification is actually being sent.
+
+	   original patch by Opsview Team
+	*/
+	create_notification_list_from_service(&mac, svc, options, &escalated, type);
 
 #ifdef USE_EVENT_BROKER
 	/* send data to event broker */
@@ -696,12 +713,6 @@ int notify_contact_of_service(nagios_macros *mac, contact *cntct, service *svc,
 
 
 	log_debug_info(DEBUGL_FUNCTIONS, 0, "notify_contact_of_service()\n");
-	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "** Attempting to notifying contact '%s'...\n", cntct->name);
-
-	/* check viability of notifying this user */
-	/* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */
-	if(check_contact_service_notification_viability(cntct, svc, type, options) == ERROR)
-		return ERROR;
 
 	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "** Notifying contact '%s'\n", cntct->name);
 
@@ -908,8 +919,8 @@ int should_service_notification_be_escalated(service *svc) {
 	}
 
 
-/* given a service, create a list of contacts to be notified, removing duplicates */
-int create_notification_list_from_service(nagios_macros *mac, service *svc, int options, int *escalated) {
+/* given a service, create a list of contacts to be notified, removing duplicates, checking contact notification viability */
+int create_notification_list_from_service(nagios_macros *mac, service *svc, int options, int *escalated, int type) {
 	serviceescalation *temp_se = NULL;
 	contactsmember *temp_contactsmember = NULL;
 	contact *temp_contact = NULL;
@@ -954,7 +965,11 @@ int create_notification_list_from_service(nagios_macros *mac, service *svc, int
 			for(temp_contactsmember = temp_se->contacts; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 				if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 					continue;
-				add_notification(mac, temp_contact);
+				/* check now if the contact can be notified */
+				if (check_contact_service_notification_viability(temp_contact, svc, type, options) == OK)
+					add_notification(mac, temp_contact);
+				else
+					log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n",temp_contact->name);
 				}
 
 			log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Adding members of contact groups from service escalation(s) to notification list.\n");
@@ -967,7 +982,11 @@ int create_notification_list_from_service(nagios_macros *mac, service *svc, int
 				for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 					if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 						continue;
-					add_notification(mac, temp_contact);
+					/* check now if the contact can be notified */
+					if (check_contact_service_notification_viability(temp_contact, svc, type, options) == OK)
+						add_notification(mac, temp_contact);
+					else
+						log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n",temp_contact->name);
 					}
 				}
 			}
@@ -982,7 +1001,11 @@ int create_notification_list_from_service(nagios_macros *mac, service *svc, int
 		for(temp_contactsmember = svc->contacts; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 			if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 				continue;
-			add_notification(mac, temp_contact);
+			/* check now if the contact can be notified */
+                        if (check_contact_service_notification_viability(temp_contact, svc, type, options) == OK)
+                                add_notification(mac, temp_contact);
+                        else
+                                log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n",temp_contact->name);
 			}
 
 		/* add all contacts that belong to contactgroups for this service */
@@ -993,7 +1016,11 @@ int create_notification_list_from_service(nagios_macros *mac, service *svc, int
 			for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 				if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 					continue;
-				add_notification(mac, temp_contact);
+	                        /* check now if the contact can be notified */
+	                        if (check_contact_service_notification_viability(temp_contact, svc, type, options) == OK)
+                                	add_notification(mac, temp_contact);
+	                        else
+	                                log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n",temp_contact->name);
 				}
 			}
 		}
@@ -1057,7 +1084,22 @@ int host_notification(host *hst, int type, char *not_author, char *not_data, int
 	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Creating list of contacts to be notified.\n");
 
 	/* create the contact notification list for this host */
-	create_notification_list_from_host(&mac, hst, options, &escalated);
+
+        /* 2011-11-01 MF:  
+           check viability before adding a contact
+           to the notification list, requires type
+           this prevents us from running through all
+           the steps until notify_contact_of_host|service
+           is reached. furthermore the $NOTIFICATIONRECIPIENTS$
+           macro only gets populated with actual recipients,
+           not all contacts assigned to that host|service.
+
+           note: checks against timeperiod will happen now(),
+           and not when the notification is actually being sent.
+
+           original patch by Opsview Team
+        */
+	create_notification_list_from_host(&mac, hst, options, &escalated, type);
 
 #ifdef USE_EVENT_BROKER
 	/* send data to event broker */
@@ -1600,12 +1642,6 @@ int notify_contact_of_host(nagios_macros *mac, contact *cntct, host *hst, int ty
 
 
 	log_debug_info(DEBUGL_FUNCTIONS, 0, "notify_contact_of_host()\n");
-	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "** Attempting to notifying contact '%s'...\n", cntct->name);
-
-	/* check viability of notifying this user about the host */
-	/* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */
-	if(check_contact_host_notification_viability(cntct, hst, type, options) == ERROR)
-		return ERROR;
 
 	log_debug_info(DEBUGL_NOTIFICATIONS, 2, "** Notifying contact '%s'\n", cntct->name);
 
@@ -1812,8 +1848,8 @@ int should_host_notification_be_escalated(host *hst) {
 	}
 
 
-/* given a host, create a list of contacts to be notified, removing duplicates */
-int create_notification_list_from_host(nagios_macros *mac, host *hst, int options, int *escalated) {
+/* given a host, create a list of contacts to be notified, removing duplicates, checking contact notification viability */
+int create_notification_list_from_host(nagios_macros *mac, host *hst, int options, int *escalated, int type) {
 	hostescalation *temp_he = NULL;
 	contactsmember *temp_contactsmember = NULL;
 	contact *temp_contact = NULL;
@@ -1857,7 +1893,11 @@ int create_notification_list_from_host(nagios_macros *mac, host *hst, int option
 			for(temp_contactsmember = temp_he->contacts; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 				if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 					continue;
-				add_notification(mac, temp_contact);
+				/* check now if the contact can be notified */
+				if (check_contact_host_notification_viability(temp_contact, hst, type, options) == OK)
+					add_notification(mac, temp_contact);
+				else
+					log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n", temp_contact->name);
 				}
 
 			log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Adding members of contact groups from host escalation(s) to notification list.\n");
@@ -1870,7 +1910,11 @@ int create_notification_list_from_host(nagios_macros *mac, host *hst, int option
 				for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 					if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 						continue;
-					add_notification(mac, temp_contact);
+	                                /* check now if the contact can be notified */
+	                                if (check_contact_host_notification_viability(temp_contact, hst, type, options) == OK)
+	                                        add_notification(mac, temp_contact);
+	                                else
+	                                        log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n", temp_contact->name);
 					}
 				}
 			}
@@ -1887,7 +1931,11 @@ int create_notification_list_from_host(nagios_macros *mac, host *hst, int option
 		for(temp_contactsmember = hst->contacts; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 			if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 				continue;
-			add_notification(mac, temp_contact);
+                        /* check now if the contact can be notified */
+                        if (check_contact_host_notification_viability(temp_contact, hst, type, options) == OK)
+                                add_notification(mac, temp_contact);
+                        else
+                                log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n", temp_contact->name);
 			}
 
 		log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Adding members of contact groups for host to notification list.\n");
@@ -1901,7 +1949,11 @@ int create_notification_list_from_host(nagios_macros *mac, host *hst, int option
 			for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
 				if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
 					continue;
-				add_notification(mac, temp_contact);
+	                        /* check now if the contact can be notified */
+	                        if (check_contact_host_notification_viability(temp_contact, hst, type, options) == OK)
+	                                add_notification(mac, temp_contact);
+	                        else
+	                                log_debug_info(DEBUGL_NOTIFICATIONS, 2, "Not adding contact '%s'\n", temp_contact->name);
 				}
 			}
 		}
diff --git a/include/nagios.h b/include/nagios.h
index 825182f..998dc9d 100644
--- a/include/nagios.h
+++ b/include/nagios.h
@@ -544,8 +544,8 @@ int should_host_notification_be_escalated(host *);				/* checks if a host notifi
 int host_notification(host *, int, char *, char *, int);                           	/* notify all contacts about a host (problem or recovery) */
 int check_contact_host_notification_viability(contact *, host *, int, int);	/* checks viability of notifying a contact about a host */
 int notify_contact_of_host(nagios_macros *mac, contact *, host *, int, char *, char *, int, int);        	/* notify a single contact about a host */
-int create_notification_list_from_host(nagios_macros *mac, host *, int, int *);         		/* given a host, create list of contacts to be notified (remove duplicates) */
-int create_notification_list_from_service(nagios_macros *mac, service *, int, int *);    		/* given a service, create list of contacts to be notified (remove duplicates) */
+int create_notification_list_from_host(nagios_macros *mac, host *,int,int *,int);         		/* given a host, create list of contacts to be notified (remove duplicates) */
+int create_notification_list_from_service(nagios_macros *mac, service *,int,int *,int);    		/* given a service, create list of contacts to be notified (remove duplicates) */
 int add_notification(nagios_macros *mac, contact *);						/* adds a notification instance */
 notification *find_notification(contact *);					/* finds a notification object */
 time_t get_next_host_notification_time(host *, time_t);				/* calculates nex acceptable re-notification time for a host */
-- 
1.7.7.1

