![]() |
Icinga-core 1.4.0
next gen monitoring
|
00001 /***************************************************************************** 00002 * 00003 * EVENTS.C - Timed event functions for Icinga 00004 * 00005 * Copyright (c) 1999-2010 Ethan Galstad (egalstad@nagios.org) 00006 * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors 00007 * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org) 00008 * 00009 * License: 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License version 2 as 00013 * published by the Free Software Foundation. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 * 00024 *****************************************************************************/ 00025 00026 #include "../include/config.h" 00027 #include "../include/common.h" 00028 #include "../include/downtime.h" 00029 #include "../include/comments.h" 00030 #include "../include/statusdata.h" 00031 #include "../include/icinga.h" 00032 #include "../include/broker.h" 00033 #include "../include/sretention.h" 00034 00035 /* make sure gcc3 won't hit here */ 00036 #ifndef GCCTOOOLD 00037 #include "../include/profiler.h" 00038 #endif 00039 00040 extern char *config_file; 00041 00042 extern int test_scheduling; 00043 00044 extern time_t program_start; 00045 extern time_t event_start; 00046 extern time_t last_command_check; 00047 00048 extern int sigshutdown; 00049 extern int sigrestart; 00050 00051 extern double sleep_time; 00052 extern int interval_length; 00053 extern int service_inter_check_delay_method; 00054 extern int host_inter_check_delay_method; 00055 extern int service_interleave_factor_method; 00056 extern int max_host_check_spread; 00057 extern int max_service_check_spread; 00058 00059 extern int command_check_interval; 00060 extern int check_reaper_interval; 00061 extern int service_freshness_check_interval; 00062 extern int host_freshness_check_interval; 00063 extern int auto_rescheduling_interval; 00064 extern int auto_rescheduling_window; 00065 00066 extern int check_external_commands; 00067 extern int check_orphaned_services; 00068 extern int check_orphaned_hosts; 00069 extern int check_service_freshness; 00070 extern int check_host_freshness; 00071 extern int auto_reschedule_checks; 00072 00073 extern int retain_state_information; 00074 extern int retention_update_interval; 00075 00076 extern int max_parallel_service_checks; 00077 extern int currently_running_service_checks; 00078 00079 extern int aggregate_status_updates; 00080 extern int status_update_interval; 00081 00082 extern int log_rotation_method; 00083 00084 extern int service_check_timeout; 00085 00086 extern int execute_service_checks; 00087 extern int execute_host_checks; 00088 00089 extern int child_processes_fork_twice; 00090 00091 extern int time_change_threshold; 00092 00093 /* make sure gcc3 won't hit here */ 00094 #ifndef GCCTOOOLD 00095 extern int event_profiling_enabled; 00096 #endif 00097 00098 timed_event *event_list_low=NULL; 00099 timed_event *event_list_low_tail=NULL; 00100 timed_event *event_list_high=NULL; 00101 timed_event *event_list_high_tail=NULL; 00102 00103 extern host *host_list; 00104 extern service *service_list; 00105 00106 sched_info scheduling_info; 00107 00108 00109 00110 /******************************************************************/ 00111 /************ EVENT SCHEDULING/HANDLING FUNCTIONS *****************/ 00112 /******************************************************************/ 00113 00114 /* initialize the event timing loop before we start monitoring */ 00115 void init_timing_loop(void){ 00116 host *temp_host=NULL; 00117 service *temp_service=NULL; 00118 time_t current_time=0L; 00119 unsigned long interval_to_use=0L; 00120 int total_interleave_blocks=0; 00121 int current_interleave_block=1; 00122 int interleave_block_index=0; 00123 int mult_factor=0; 00124 int is_valid_time=0; 00125 time_t next_valid_time=0L; 00126 int schedule_check=0; 00127 double max_inter_check_delay=0.0; 00128 struct timeval tv[9]; 00129 double runtime[9]; 00130 00131 00132 log_debug_info(DEBUGL_FUNCTIONS,0,"init_timing_loop() start\n"); 00133 00134 /* get the time right now */ 00135 time(¤t_time); 00136 00137 00138 /******** GET BASIC HOST/SERVICE INFO ********/ 00139 00140 scheduling_info.total_services=0; 00141 scheduling_info.total_scheduled_services=0; 00142 scheduling_info.total_hosts=0; 00143 scheduling_info.total_scheduled_hosts=0; 00144 scheduling_info.average_services_per_host=0.0; 00145 scheduling_info.average_scheduled_services_per_host=0.0; 00146 scheduling_info.average_service_execution_time=0.0; 00147 scheduling_info.service_check_interval_total=0; 00148 scheduling_info.average_service_inter_check_delay=0.0; 00149 scheduling_info.host_check_interval_total=0; 00150 scheduling_info.average_host_inter_check_delay=0.0; 00151 00152 if(test_scheduling==TRUE) 00153 gettimeofday(&tv[0],NULL); 00154 00155 /* get info on service checks to be scheduled */ 00156 for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){ 00157 00158 schedule_check=TRUE; 00159 00160 /* service has no check interval */ 00161 if(temp_service->check_interval==0) 00162 schedule_check=FALSE; 00163 00164 /* active checks are disabled */ 00165 if(temp_service->checks_enabled==FALSE) 00166 schedule_check=FALSE; 00167 00168 /* are there any valid times this service can be checked? */ 00169 is_valid_time=check_time_against_period(current_time,temp_service->check_period_ptr); 00170 if(is_valid_time==ERROR){ 00171 get_next_valid_time(current_time,&next_valid_time,temp_service->check_period_ptr); 00172 if(current_time==next_valid_time) 00173 schedule_check=FALSE; 00174 } 00175 00176 if(schedule_check==TRUE){ 00177 00178 scheduling_info.total_scheduled_services++; 00179 00180 /* used later in inter-check delay calculations */ 00181 scheduling_info.service_check_interval_total+=temp_service->check_interval; 00182 00183 /* calculate rolling average execution time (available from retained state information) */ 00184 scheduling_info.average_service_execution_time=(double)(((scheduling_info.average_service_execution_time*(scheduling_info.total_scheduled_services-1)) + temp_service->execution_time)/(double)scheduling_info.total_scheduled_services); 00185 } 00186 else{ 00187 temp_service->should_be_scheduled=FALSE; 00188 00189 log_debug_info(DEBUGL_EVENTS,1,"Service '%s' on host '%s' should not be scheduled.\n",temp_service->description,temp_service->host_name); 00190 } 00191 00192 scheduling_info.total_services++; 00193 } 00194 00195 if(test_scheduling==TRUE) 00196 gettimeofday(&tv[1],NULL); 00197 00198 /* get info on host checks to be scheduled */ 00199 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ 00200 00201 schedule_check=TRUE; 00202 00203 /* host has no check interval */ 00204 if(temp_host->check_interval==0) 00205 schedule_check=FALSE; 00206 00207 /* active checks are disabled */ 00208 if(temp_host->checks_enabled==FALSE) 00209 schedule_check=FALSE; 00210 00211 /* are there any valid times this host can be checked? */ 00212 is_valid_time=check_time_against_period(current_time,temp_host->check_period_ptr); 00213 if(is_valid_time==ERROR){ 00214 get_next_valid_time(current_time,&next_valid_time,temp_host->check_period_ptr); 00215 if(current_time==next_valid_time) 00216 schedule_check=FALSE; 00217 } 00218 00219 if(schedule_check==TRUE){ 00220 00221 scheduling_info.total_scheduled_hosts++; 00222 00223 /* this is used later in inter-check delay calculations */ 00224 scheduling_info.host_check_interval_total+=temp_host->check_interval; 00225 } 00226 else{ 00227 temp_host->should_be_scheduled=FALSE; 00228 00229 log_debug_info(DEBUGL_EVENTS,1,"Host '%s' should not be scheduled.\n",temp_host->name); 00230 } 00231 00232 scheduling_info.total_hosts++; 00233 } 00234 00235 if(test_scheduling==TRUE) 00236 gettimeofday(&tv[2],NULL); 00237 00238 scheduling_info.average_services_per_host=(double)((double)scheduling_info.total_services/(double)scheduling_info.total_hosts); 00239 scheduling_info.average_scheduled_services_per_host=(double)((double)scheduling_info.total_scheduled_services/(double)scheduling_info.total_hosts); 00240 00241 /* adjust the check interval total to correspond to the interval length */ 00242 scheduling_info.service_check_interval_total=(scheduling_info.service_check_interval_total*interval_length); 00243 00244 /* calculate the average check interval for services */ 00245 scheduling_info.average_service_check_interval=(double)((double)scheduling_info.service_check_interval_total/(double)scheduling_info.total_scheduled_services); 00246 00247 00248 /******** DETERMINE SERVICE SCHEDULING PARAMS ********/ 00249 00250 log_debug_info(DEBUGL_EVENTS,2,"Determining service scheduling parameters..."); 00251 00252 /* default max service check spread (in minutes) */ 00253 scheduling_info.max_service_check_spread=max_service_check_spread; 00254 00255 /* how should we determine the service inter-check delay to use? */ 00256 switch(service_inter_check_delay_method){ 00257 00258 case ICD_NONE: 00259 00260 /* don't spread checks out - useful for testing parallelization code */ 00261 scheduling_info.service_inter_check_delay=0.0; 00262 break; 00263 00264 case ICD_DUMB: 00265 00266 /* be dumb and just schedule checks 1 second apart */ 00267 scheduling_info.service_inter_check_delay=1.0; 00268 break; 00269 00270 case ICD_USER: 00271 00272 /* the user specified a delay, so don't try to calculate one */ 00273 break; 00274 00275 case ICD_SMART: 00276 default: 00277 00278 /* be smart and calculate the best delay to use to minimize local load... */ 00279 if(scheduling_info.total_scheduled_services>0 && scheduling_info.service_check_interval_total>0){ 00280 00281 /* calculate the average inter check delay (in seconds) needed to evenly space the service checks out */ 00282 scheduling_info.average_service_inter_check_delay=(double)(scheduling_info.average_service_check_interval/(double)scheduling_info.total_scheduled_services); 00283 00284 /* set the global inter check delay value */ 00285 scheduling_info.service_inter_check_delay=scheduling_info.average_service_inter_check_delay; 00286 00287 /* calculate max inter check delay and see if we should use that instead */ 00288 max_inter_check_delay=(double)((scheduling_info.max_service_check_spread*60.0)/(double)scheduling_info.total_scheduled_services); 00289 if(scheduling_info.service_inter_check_delay>max_inter_check_delay) 00290 scheduling_info.service_inter_check_delay=max_inter_check_delay; 00291 } 00292 else 00293 scheduling_info.service_inter_check_delay=0.0; 00294 00295 log_debug_info(DEBUGL_EVENTS,1,"Total scheduled service checks: %d\n",scheduling_info.total_scheduled_services); 00296 log_debug_info(DEBUGL_EVENTS,1,"Average service check interval: %0.2f sec\n",scheduling_info.average_service_check_interval); 00297 log_debug_info(DEBUGL_EVENTS,1,"Service inter-check delay: %0.2f sec\n",scheduling_info.service_inter_check_delay); 00298 } 00299 00300 /* how should we determine the service interleave factor? */ 00301 switch(service_interleave_factor_method){ 00302 00303 case ILF_USER: 00304 00305 /* the user supplied a value, so don't do any calculation */ 00306 break; 00307 00308 case ILF_SMART: 00309 default: 00310 00311 /* protect against a divide by zero problem - shouldn't happen, but just in case... */ 00312 if(scheduling_info.total_hosts==0) 00313 scheduling_info.total_hosts=1; 00314 00315 scheduling_info.service_interleave_factor=(int)(ceil(scheduling_info.average_scheduled_services_per_host)); 00316 00317 log_debug_info(DEBUGL_EVENTS,1,"Total scheduled service checks: %d\n",scheduling_info.total_scheduled_services); 00318 log_debug_info(DEBUGL_EVENTS,1,"Total hosts: %d\n",scheduling_info.total_hosts); 00319 log_debug_info(DEBUGL_EVENTS,1,"Service Interleave factor: %d\n",scheduling_info.service_interleave_factor); 00320 } 00321 00322 /* calculate number of service interleave blocks */ 00323 if(scheduling_info.service_interleave_factor==0) 00324 total_interleave_blocks=scheduling_info.total_scheduled_services; 00325 else 00326 total_interleave_blocks=(int)ceil((double)scheduling_info.total_scheduled_services/(double)scheduling_info.service_interleave_factor); 00327 00328 scheduling_info.first_service_check=(time_t)0L; 00329 scheduling_info.last_service_check=(time_t)0L; 00330 00331 log_debug_info(DEBUGL_EVENTS,1,"Total scheduled services: %d\n",scheduling_info.total_scheduled_services); 00332 log_debug_info(DEBUGL_EVENTS,1,"Service Interleave factor: %d\n",scheduling_info.service_interleave_factor); 00333 log_debug_info(DEBUGL_EVENTS,1,"Total service interleave blocks: %d\n",total_interleave_blocks); 00334 log_debug_info(DEBUGL_EVENTS,1,"Service inter-check delay: %2.1f\n",scheduling_info.service_inter_check_delay); 00335 00336 00337 if(test_scheduling==TRUE) 00338 gettimeofday(&tv[3],NULL); 00339 00340 /******** SCHEDULE SERVICE CHECKS ********/ 00341 00342 log_debug_info(DEBUGL_EVENTS,2,"Scheduling service checks..."); 00343 00344 /* determine check times for service checks (with interleaving to minimize remote load) */ 00345 current_interleave_block=0; 00346 for(temp_service=service_list;temp_service!=NULL && scheduling_info.service_interleave_factor>0;){ 00347 00348 log_debug_info(DEBUGL_EVENTS,2,"Current Interleave Block: %d\n",current_interleave_block); 00349 00350 for(interleave_block_index=0;interleave_block_index<scheduling_info.service_interleave_factor && temp_service!=NULL;temp_service=temp_service->next){ 00351 00352 log_debug_info(DEBUGL_EVENTS,2,"Service '%s' on host '%s'\n",temp_service->description,temp_service->host_name); 00353 /* skip this service if it shouldn't be scheduled */ 00354 if(temp_service->should_be_scheduled==FALSE){ 00355 log_debug_info(DEBUGL_EVENTS,2,"Service check should not be scheduled.\n"); 00356 continue; 00357 } 00358 00359 /* skip services that are already scheduled for the future (from retention data), but reschedule ones that were supposed to happen while we weren't running... */ 00360 if(temp_service->next_check>current_time){ 00361 log_debug_info(DEBUGL_EVENTS,2,"Service is already scheduled to be checked in the future: %s\n",ctime(&temp_service->next_check)); 00362 continue; 00363 } 00364 00365 /* interleave block index should only be increased when we find a schedulable service */ 00366 /* moved from for() loop 11/05/05 EG */ 00367 interleave_block_index++; 00368 00369 mult_factor=current_interleave_block+(interleave_block_index*total_interleave_blocks); 00370 00371 log_debug_info(DEBUGL_EVENTS,2,"CIB: %d, IBI: %d, TIB: %d, SIF: %d\n",current_interleave_block,interleave_block_index,total_interleave_blocks,scheduling_info.service_interleave_factor); 00372 log_debug_info(DEBUGL_EVENTS,2,"Mult factor: %d\n",mult_factor); 00373 00374 /* set the preferred next check time for the service */ 00375 temp_service->next_check=(time_t)(current_time+(mult_factor*scheduling_info.service_inter_check_delay)); 00376 00377 log_debug_info(DEBUGL_EVENTS,2,"Preferred Check Time: %lu --> %s",(unsigned long)temp_service->next_check,ctime(&temp_service->next_check)); 00378 00379 00380 /* make sure the service can actually be scheduled when we want */ 00381 is_valid_time=check_time_against_period(temp_service->next_check,temp_service->check_period_ptr); 00382 if(is_valid_time==ERROR){ 00383 log_debug_info(DEBUGL_EVENTS,2,"Preferred Time is Invalid In Timeperiod '%s': %lu --> %s",temp_service->check_period_ptr->name,(unsigned long)temp_service->next_check,ctime(&temp_service->next_check)); 00384 get_next_valid_time(temp_service->next_check,&next_valid_time,temp_service->check_period_ptr); 00385 temp_service->next_check=next_valid_time; 00386 } 00387 00388 log_debug_info(DEBUGL_EVENTS,2,"Actual Check Time: %lu --> %s",(unsigned long)temp_service->next_check,ctime(&temp_service->next_check)); 00389 00390 if(scheduling_info.first_service_check==(time_t)0 || (temp_service->next_check<scheduling_info.first_service_check)) 00391 scheduling_info.first_service_check=temp_service->next_check; 00392 if(temp_service->next_check > scheduling_info.last_service_check) 00393 scheduling_info.last_service_check=temp_service->next_check; 00394 } 00395 00396 current_interleave_block++; 00397 } 00398 00399 if(test_scheduling==TRUE) 00400 gettimeofday(&tv[4],NULL); 00401 00402 /* add scheduled service checks to event queue */ 00403 for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){ 00404 00405 /* update status of all services (scheduled or not) */ 00406 update_service_status(temp_service,FALSE); 00407 00408 /* skip most services that shouldn't be scheduled */ 00409 if(temp_service->should_be_scheduled==FALSE){ 00410 00411 /* passive checks are an exception if a forced check was scheduled before Icinga was restarted */ 00412 if(!(temp_service->checks_enabled==FALSE && temp_service->next_check!=(time_t)0L && (temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION))) 00413 continue; 00414 } 00415 00416 /* create a new service check event */ 00417 schedule_new_event(EVENT_SERVICE_CHECK,FALSE,temp_service->next_check,FALSE,0,NULL,TRUE,(void *)temp_service,NULL,temp_service->check_options); 00418 } 00419 00420 00421 if(test_scheduling==TRUE) 00422 gettimeofday(&tv[5],NULL); 00423 00424 /******** DETERMINE HOST SCHEDULING PARAMS ********/ 00425 00426 log_debug_info(DEBUGL_EVENTS,2,"Determining host scheduling parameters..."); 00427 00428 scheduling_info.first_host_check=(time_t)0L; 00429 scheduling_info.last_host_check=(time_t)0L; 00430 00431 /* default max host check spread (in minutes) */ 00432 scheduling_info.max_host_check_spread=max_host_check_spread; 00433 00434 /* how should we determine the host inter-check delay to use? */ 00435 switch(host_inter_check_delay_method){ 00436 00437 case ICD_NONE: 00438 00439 /* don't spread checks out */ 00440 scheduling_info.host_inter_check_delay=0.0; 00441 break; 00442 00443 case ICD_DUMB: 00444 00445 /* be dumb and just schedule checks 1 second apart */ 00446 scheduling_info.host_inter_check_delay=1.0; 00447 break; 00448 00449 case ICD_USER: 00450 00451 /* the user specified a delay, so don't try to calculate one */ 00452 break; 00453 00454 case ICD_SMART: 00455 default: 00456 00457 /* be smart and calculate the best delay to use to minimize local load... */ 00458 if(scheduling_info.total_scheduled_hosts>0 && scheduling_info.host_check_interval_total>0){ 00459 00460 /* adjust the check interval total to correspond to the interval length */ 00461 scheduling_info.host_check_interval_total=(scheduling_info.host_check_interval_total*interval_length); 00462 00463 /* calculate the average check interval for hosts */ 00464 scheduling_info.average_host_check_interval=(double)((double)scheduling_info.host_check_interval_total/(double)scheduling_info.total_scheduled_hosts); 00465 00466 /* calculate the average inter check delay (in seconds) needed to evenly space the host checks out */ 00467 scheduling_info.average_host_inter_check_delay=(double)(scheduling_info.average_host_check_interval/(double)scheduling_info.total_scheduled_hosts); 00468 00469 /* set the global inter check delay value */ 00470 scheduling_info.host_inter_check_delay=scheduling_info.average_host_inter_check_delay; 00471 00472 /* calculate max inter check delay and see if we should use that instead */ 00473 max_inter_check_delay=(double)((scheduling_info.max_host_check_spread*60.0)/(double)scheduling_info.total_scheduled_hosts); 00474 if(scheduling_info.host_inter_check_delay>max_inter_check_delay) 00475 scheduling_info.host_inter_check_delay=max_inter_check_delay; 00476 } 00477 else 00478 scheduling_info.host_inter_check_delay=0.0; 00479 00480 log_debug_info(DEBUGL_EVENTS,2,"Total scheduled host checks: %d\n",scheduling_info.total_scheduled_hosts); 00481 log_debug_info(DEBUGL_EVENTS,2,"Host check interval total: %lu\n",scheduling_info.host_check_interval_total); 00482 log_debug_info(DEBUGL_EVENTS,2,"Average host check interval: %0.2f sec\n",scheduling_info.average_host_check_interval); 00483 log_debug_info(DEBUGL_EVENTS,2,"Host inter-check delay: %0.2f sec\n",scheduling_info.host_inter_check_delay); 00484 } 00485 00486 if(test_scheduling==TRUE) 00487 gettimeofday(&tv[6],NULL); 00488 00489 00490 /******** SCHEDULE HOST CHECKS ********/ 00491 00492 log_debug_info(DEBUGL_EVENTS,2,"Scheduling host checks..."); 00493 00494 /* determine check times for host checks */ 00495 mult_factor=0; 00496 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ 00497 00498 log_debug_info(DEBUGL_EVENTS,2,"Host '%s'\n",temp_host->name); 00499 00500 /* skip hosts that shouldn't be scheduled */ 00501 if(temp_host->should_be_scheduled==FALSE){ 00502 log_debug_info(DEBUGL_EVENTS,2,"Host check should not be scheduled.\n"); 00503 continue; 00504 } 00505 00506 /* skip hosts that are already scheduled for the future (from retention data), but reschedule ones that were supposed to be checked before we started */ 00507 if(temp_host->next_check>current_time){ 00508 log_debug_info(DEBUGL_EVENTS,2,"Host is already scheduled to be checked in the future: %s\n",ctime(&temp_host->next_check)); 00509 continue; 00510 } 00511 00512 /* calculate preferred host check time */ 00513 temp_host->next_check=(time_t)(current_time+(mult_factor*scheduling_info.host_inter_check_delay)); 00514 00515 log_debug_info(DEBUGL_EVENTS,2,"Preferred Check Time: %lu --> %s",(unsigned long)temp_host->next_check,ctime(&temp_host->next_check)); 00516 00517 /* make sure the host can actually be scheduled at this time */ 00518 is_valid_time=check_time_against_period(temp_host->next_check,temp_host->check_period_ptr); 00519 if(is_valid_time==ERROR){ 00520 get_next_valid_time(temp_host->next_check,&next_valid_time,temp_host->check_period_ptr); 00521 temp_host->next_check=next_valid_time; 00522 } 00523 00524 log_debug_info(DEBUGL_EVENTS,2,"Actual Check Time: %lu --> %s",(unsigned long)temp_host->next_check,ctime(&temp_host->next_check)); 00525 00526 if(scheduling_info.first_host_check==(time_t)0 || (temp_host->next_check<scheduling_info.first_host_check)) 00527 scheduling_info.first_host_check=temp_host->next_check; 00528 if(temp_host->next_check > scheduling_info.last_host_check) 00529 scheduling_info.last_host_check=temp_host->next_check; 00530 00531 mult_factor++; 00532 } 00533 00534 if(test_scheduling==TRUE) 00535 gettimeofday(&tv[7],NULL); 00536 00537 /* add scheduled host checks to event queue */ 00538 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ 00539 00540 /* update status of all hosts (scheduled or not) */ 00541 update_host_status(temp_host,FALSE); 00542 00543 /* skip most hosts that shouldn't be scheduled */ 00544 if(temp_host->should_be_scheduled==FALSE){ 00545 00546 /* passive checks are an exception if a forced check was scheduled before Icinga was restarted */ 00547 if(!(temp_host->checks_enabled==FALSE && temp_host->next_check!=(time_t)0L && (temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION))) 00548 continue; 00549 } 00550 00551 /* schedule a new host check event */ 00552 schedule_new_event(EVENT_HOST_CHECK,FALSE,temp_host->next_check,FALSE,0,NULL,TRUE,(void *)temp_host,NULL,temp_host->check_options); 00553 } 00554 00555 if(test_scheduling==TRUE) 00556 gettimeofday(&tv[8],NULL); 00557 00558 00559 /******** SCHEDULE MISC EVENTS ********/ 00560 00561 /* add a host and service check rescheduling event */ 00562 if(auto_reschedule_checks==TRUE) 00563 schedule_new_event(EVENT_RESCHEDULE_CHECKS,TRUE,current_time+auto_rescheduling_interval,TRUE,auto_rescheduling_interval,NULL,TRUE,NULL,NULL,0); 00564 00565 /* add a check result reaper event */ 00566 schedule_new_event(EVENT_CHECK_REAPER,TRUE,current_time+check_reaper_interval,TRUE,check_reaper_interval,NULL,TRUE,NULL,NULL,0); 00567 00568 /* add an orphaned check event */ 00569 if(check_orphaned_services==TRUE || check_orphaned_hosts==TRUE) 00570 schedule_new_event(EVENT_ORPHAN_CHECK,TRUE,current_time+DEFAULT_ORPHAN_CHECK_INTERVAL,TRUE,DEFAULT_ORPHAN_CHECK_INTERVAL,NULL,TRUE,NULL,NULL,0); 00571 00572 /* add a service result "freshness" check event */ 00573 if(check_service_freshness==TRUE) 00574 schedule_new_event(EVENT_SFRESHNESS_CHECK,TRUE,current_time+service_freshness_check_interval,TRUE,service_freshness_check_interval,NULL,TRUE,NULL,NULL,0); 00575 00576 /* add a host result "freshness" check event */ 00577 if(check_host_freshness==TRUE) 00578 schedule_new_event(EVENT_HFRESHNESS_CHECK,TRUE,current_time+host_freshness_check_interval,TRUE,host_freshness_check_interval,NULL,TRUE,NULL,NULL,0); 00579 00580 /* add a status save event */ 00581 if(aggregate_status_updates==TRUE) 00582 schedule_new_event(EVENT_STATUS_SAVE,TRUE,current_time+status_update_interval,TRUE,status_update_interval,NULL,TRUE,NULL,NULL,0); 00583 00584 /* add an external command check event if needed */ 00585 if(check_external_commands==TRUE){ 00586 if(command_check_interval==-1) 00587 interval_to_use=(unsigned long)60; 00588 else 00589 interval_to_use=(unsigned long)command_check_interval; 00590 schedule_new_event(EVENT_COMMAND_CHECK,TRUE,current_time+interval_to_use,TRUE,interval_to_use,NULL,TRUE,NULL,NULL,0); 00591 } 00592 00593 /* add a log rotation event if necessary */ 00594 if(log_rotation_method!=LOG_ROTATION_NONE) 00595 schedule_new_event(EVENT_LOG_ROTATION,TRUE,get_next_log_rotation_time(),TRUE,0,(void *)get_next_log_rotation_time,TRUE,NULL,NULL,0); 00596 00597 /* add a retention data save event if needed */ 00598 if(retain_state_information==TRUE && retention_update_interval>0) 00599 schedule_new_event(EVENT_RETENTION_SAVE,TRUE,current_time+(retention_update_interval*60),TRUE,(retention_update_interval*60),NULL,TRUE,NULL,NULL,0); 00600 00601 if(test_scheduling==TRUE){ 00602 00603 runtime[0]=(double)((double)(tv[1].tv_sec-tv[0].tv_sec)+(double)((tv[1].tv_usec-tv[0].tv_usec)/1000.0)/1000.0); 00604 runtime[1]=(double)((double)(tv[2].tv_sec-tv[1].tv_sec)+(double)((tv[2].tv_usec-tv[1].tv_usec)/1000.0)/1000.0); 00605 runtime[2]=(double)((double)(tv[3].tv_sec-tv[2].tv_sec)+(double)((tv[3].tv_usec-tv[2].tv_usec)/1000.0)/1000.0); 00606 runtime[3]=(double)((double)(tv[4].tv_sec-tv[3].tv_sec)+(double)((tv[4].tv_usec-tv[3].tv_usec)/1000.0)/1000.0); 00607 runtime[4]=(double)((double)(tv[5].tv_sec-tv[4].tv_sec)+(double)((tv[5].tv_usec-tv[4].tv_usec)/1000.0)/1000.0); 00608 runtime[5]=(double)((double)(tv[6].tv_sec-tv[5].tv_sec)+(double)((tv[6].tv_usec-tv[5].tv_usec)/1000.0)/1000.0); 00609 runtime[6]=(double)((double)(tv[7].tv_sec-tv[6].tv_sec)+(double)((tv[7].tv_usec-tv[6].tv_usec)/1000.0)/1000.0); 00610 runtime[7]=(double)((double)(tv[8].tv_sec-tv[7].tv_sec)+(double)((tv[8].tv_usec-tv[7].tv_usec)/1000.0)/1000.0); 00611 00612 runtime[8]=(double)((double)(tv[8].tv_sec-tv[0].tv_sec)+(double)((tv[8].tv_usec-tv[0].tv_usec)/1000.0)/1000.0); 00613 00614 printf("EVENT SCHEDULING TIMES\n"); 00615 printf("-------------------------------------\n"); 00616 printf("Get service info: %.6lf sec\n",runtime[0]); 00617 printf("Get host info info: %.6lf sec\n",runtime[1]); 00618 printf("Get service params: %.6lf sec\n",runtime[2]); 00619 printf("Schedule service times: %.6lf sec\n",runtime[3]); 00620 printf("Schedule service events: %.6lf sec\n",runtime[4]); 00621 printf("Get host params: %.6lf sec\n",runtime[5]); 00622 printf("Schedule host times: %.6lf sec\n",runtime[6]); 00623 printf("Schedule host events: %.6lf sec\n",runtime[7]); 00624 printf(" ============\n"); 00625 printf("TOTAL: %.6lf sec\n",runtime[8]); 00626 printf("\n\n"); 00627 } 00628 00629 log_debug_info(DEBUGL_FUNCTIONS,0,"init_timing_loop() end\n"); 00630 00631 return; 00632 } 00633 00634 00635 /*gives information about a particular event*/ 00636 void display_event_data(timed_event* event, int priority){ 00637 00638 service *temp_service=NULL; 00639 host *temp_host=NULL; 00640 00641 printf("\t\tEvent:"); 00642 00643 switch(event->event_type){ 00644 00645 case EVENT_SERVICE_CHECK: 00646 printf("\t\t(service check)\n"); 00647 temp_service=(service *)event->event_data; 00648 printf("\t\tService Description: %s\n",temp_service->description); 00649 printf("\t\tAssociated Host: %s\n",temp_service->host_name); 00650 break; 00651 00652 case EVENT_HOST_CHECK: 00653 printf("\t\t(host check)\n"); 00654 temp_host=(host *)event->event_data; 00655 printf("\t\tHost: %s\n",temp_host->name); 00656 /* run a host check */ 00657 break; 00658 00659 case EVENT_COMMAND_CHECK: 00660 printf("\t\t(external command check)\n"); 00661 break; 00662 00663 case EVENT_LOG_ROTATION: 00664 printf("\t\t(log file rotation)\n"); 00665 break; 00666 00667 case EVENT_PROGRAM_SHUTDOWN: 00668 printf("\t\t(program shutdown)\n"); 00669 break; 00670 00671 case EVENT_PROGRAM_RESTART: 00672 printf("\t\t(program restart)\n"); 00673 break; 00674 00675 case EVENT_CHECK_REAPER: 00676 printf("\t\t(service check reaper)\n"); 00677 break; 00678 00679 case EVENT_ORPHAN_CHECK: 00680 printf("\t\t(orphaned service check)\n"); 00681 break; 00682 00683 case EVENT_RETENTION_SAVE: 00684 printf("\t\t(retention save)\n"); 00685 break; 00686 00687 case EVENT_STATUS_SAVE: 00688 printf("\t\t(status save)\n"); 00689 break; 00690 00691 case EVENT_SCHEDULED_DOWNTIME: 00692 printf("\t\t(scheduled downtime)\n"); 00693 break; 00694 00695 case EVENT_SFRESHNESS_CHECK: 00696 printf("\t\t(service result freshness check)\n"); 00697 break; 00698 00699 case EVENT_HFRESHNESS_CHECK: 00700 printf("\t\t(host result freshness check)\n"); 00701 break; 00702 00703 case EVENT_EXPIRE_DOWNTIME: 00704 printf("\t\t(expire downtime)\n"); 00705 break; 00706 00707 case EVENT_RESCHEDULE_CHECKS: 00708 printf("\t\t(reschedule checks)\n"); 00709 break; 00710 00711 case EVENT_EXPIRE_COMMENT: 00712 printf("\t\t(expire comment)\n"); 00713 break; 00714 00715 case EVENT_USER_FUNCTION: 00716 printf("\t\t(user function)\n"); 00717 break; 00718 00719 default: 00720 printf("\t\t(Unknown!!!)\n"); 00721 break; 00722 00723 } 00724 00725 printf("\t\tPriority %s\n", (priority == 0 ?"Low":"High")); 00726 printf("\t\tInterval: %lu\n",event->event_interval); 00727 printf("\t\tEvent Time: %s\n",ctime(&event->run_time)); 00728 printf("\n\n"); 00729 } 00730 00731 00732 /* displays the service check scheduling queue */ 00733 void display_schedule(void){ 00734 timed_event* high_event=NULL; 00735 timed_event* low_event=NULL; 00736 timed_event* event=NULL; 00737 int priority=0; 00738 00739 printf("*** The current scheduling queue is listed below ***\n"); 00740 00741 high_event = event_list_high; 00742 low_event = event_list_low; 00743 00744 while(high_event || low_event){ 00745 if(low_event && high_event){ 00746 if(low_event->run_time < high_event->run_time){ 00747 event = low_event; 00748 low_event = low_event->next; 00749 priority = 0; 00750 }else{ 00751 event = high_event; 00752 high_event = high_event->next; 00753 priority = 1; 00754 } 00755 }else{ 00756 if(high_event){ 00757 event = high_event; 00758 high_event = high_event->next; 00759 priority = 1; 00760 } 00761 00762 if(low_event){ 00763 event = low_event; 00764 low_event = low_event->next; 00765 priority = 0; 00766 } 00767 } 00768 00769 display_event_data(event, priority); 00770 } 00771 } 00772 00773 00774 /* displays service check scheduling information */ 00775 void display_scheduling_info(void){ 00776 float minimum_concurrent_checks1=0.0; 00777 float minimum_concurrent_checks2=0.0; 00778 float minimum_concurrent_checks=0.0; 00779 float max_reaper_interval=0.0; 00780 int suggestions=0; 00781 00782 printf("Projected scheduling information for host and service checks\n"); 00783 printf("is listed below. This information assumes that you are going\n"); 00784 printf("to start running %s with your current config files.\n\n", PROGRAM_NAME); 00785 00786 printf("HOST SCHEDULING INFORMATION\n"); 00787 printf("---------------------------\n"); 00788 printf("Total hosts: %d\n",scheduling_info.total_hosts); 00789 printf("Total scheduled hosts: %d\n",scheduling_info.total_scheduled_hosts); 00790 00791 printf("Host inter-check delay method: "); 00792 if(host_inter_check_delay_method==ICD_NONE) 00793 printf("NONE\n"); 00794 else if(host_inter_check_delay_method==ICD_DUMB) 00795 printf("DUMB\n"); 00796 else if(host_inter_check_delay_method==ICD_SMART){ 00797 printf("SMART\n"); 00798 printf("Average host check interval: %.2f sec\n",scheduling_info.average_host_check_interval); 00799 } 00800 else 00801 printf("USER-SUPPLIED VALUE\n"); 00802 printf("Host inter-check delay: %.2f sec\n",scheduling_info.host_inter_check_delay); 00803 printf("Max host check spread: %d min\n",scheduling_info.max_host_check_spread); 00804 printf("First scheduled check: %s",(scheduling_info.total_scheduled_hosts==0)?"N/A\n":ctime(&scheduling_info.first_host_check)); 00805 printf("Last scheduled check: %s",(scheduling_info.total_scheduled_hosts==0)?"N/A\n":ctime(&scheduling_info.last_host_check)); 00806 printf("\n\n"); 00807 00808 printf("SERVICE SCHEDULING INFORMATION\n"); 00809 printf("-------------------------------\n"); 00810 printf("Total services: %d\n",scheduling_info.total_services); 00811 printf("Total scheduled services: %d\n",scheduling_info.total_scheduled_services); 00812 00813 printf("Service inter-check delay method: "); 00814 if(service_inter_check_delay_method==ICD_NONE) 00815 printf("NONE\n"); 00816 else if(service_inter_check_delay_method==ICD_DUMB) 00817 printf("DUMB\n"); 00818 else if(service_inter_check_delay_method==ICD_SMART){ 00819 printf("SMART\n"); 00820 printf("Average service check interval: %.2f sec\n",scheduling_info.average_service_check_interval); 00821 } 00822 else 00823 printf("USER-SUPPLIED VALUE\n"); 00824 printf("Inter-check delay: %.2f sec\n",scheduling_info.service_inter_check_delay); 00825 00826 printf("Interleave factor method: %s\n",(service_interleave_factor_method==ILF_USER)?"USER-SUPPLIED VALUE":"SMART"); 00827 if(service_interleave_factor_method==ILF_SMART) 00828 printf("Average services per host: %.2f\n",scheduling_info.average_services_per_host); 00829 printf("Service interleave factor: %d\n",scheduling_info.service_interleave_factor); 00830 00831 printf("Max service check spread: %d min\n",scheduling_info.max_service_check_spread); 00832 printf("First scheduled check: %s",ctime(&scheduling_info.first_service_check)); 00833 printf("Last scheduled check: %s",ctime(&scheduling_info.last_service_check)); 00834 printf("\n\n"); 00835 00836 printf("CHECK PROCESSING INFORMATION\n"); 00837 printf("----------------------------\n"); 00838 printf("Check result reaper interval: %d sec\n",check_reaper_interval); 00839 printf("Max concurrent service checks: "); 00840 if(max_parallel_service_checks==0) 00841 printf("Unlimited\n"); 00842 else 00843 printf("%d\n",max_parallel_service_checks); 00844 printf("\n\n"); 00845 00846 printf("PERFORMANCE SUGGESTIONS\n"); 00847 printf("-----------------------\n"); 00848 00849 00850 /***** MAX REAPER INTERVAL RECOMMENDATION *****/ 00851 00852 /* assume a 100% (2x) check burst for check reaper */ 00853 /* assume we want a max of 2k files in the result queue at any given time */ 00854 max_reaper_interval=floor(2000*scheduling_info.service_inter_check_delay); 00855 if(max_reaper_interval<2.0) 00856 max_reaper_interval=2.0; 00857 if(max_reaper_interval>30.0) 00858 max_reaper_interval=30.0; 00859 if((int)max_reaper_interval<check_reaper_interval){ 00860 printf("* Value for 'check_result_reaper_frequency' should be <= %d seconds\n",(int)max_reaper_interval); 00861 suggestions++; 00862 } 00863 if(check_reaper_interval<2){ 00864 printf("* Value for 'check_result_reaper_frequency' should be >= 2 seconds\n"); 00865 suggestions++; 00866 } 00867 00868 /***** MINIMUM CONCURRENT CHECKS RECOMMENDATION *****/ 00869 00870 /* first method (old) - assume a 100% (2x) service check burst for max concurrent checks */ 00871 if(scheduling_info.service_inter_check_delay==0.0) 00872 minimum_concurrent_checks1=ceil(check_reaper_interval*2.0); 00873 else 00874 minimum_concurrent_checks1=ceil((check_reaper_interval*2.0)/scheduling_info.service_inter_check_delay); 00875 00876 /* second method (new) - assume a 25% (1.25x) service check burst for max concurrent checks */ 00877 minimum_concurrent_checks2=ceil((((double)scheduling_info.total_scheduled_services)/scheduling_info.average_service_check_interval) * 1.25 * check_reaper_interval * scheduling_info.average_service_execution_time); 00878 00879 /* use max of computed values */ 00880 if(minimum_concurrent_checks1>minimum_concurrent_checks2) 00881 minimum_concurrent_checks=minimum_concurrent_checks1; 00882 else 00883 minimum_concurrent_checks=minimum_concurrent_checks2; 00884 00885 /* compare with configured value */ 00886 if(((int)minimum_concurrent_checks > max_parallel_service_checks) && max_parallel_service_checks!=0){ 00887 printf("* Value for 'max_concurrent_checks' option should be >= %d\n",(int)minimum_concurrent_checks); 00888 suggestions++; 00889 } 00890 00891 if(suggestions==0) 00892 printf("I have no suggestions - things look okay.\n"); 00893 00894 printf("\n"); 00895 00896 return; 00897 } 00898 00899 00900 /* schedule a new timed event */ 00901 int schedule_new_event(int event_type, int high_priority, time_t run_time, int recurring, unsigned long event_interval, void *timing_func, int compensate_for_time_change, void *event_data, void *event_args, int event_options){ 00902 timed_event **event_list=NULL; 00903 timed_event **event_list_tail=NULL; 00904 timed_event *new_event=NULL; 00905 00906 log_debug_info(DEBUGL_FUNCTIONS,0,"schedule_new_event()\n"); 00907 00908 if(high_priority==TRUE){ 00909 event_list=&event_list_high; 00910 event_list_tail=&event_list_high_tail; 00911 } 00912 else{ 00913 event_list=&event_list_low; 00914 event_list_tail=&event_list_low_tail; 00915 } 00916 00917 new_event=(timed_event *)malloc(sizeof(timed_event)); 00918 if(new_event!=NULL){ 00919 new_event->event_type=event_type; 00920 new_event->event_data=event_data; 00921 new_event->event_args=event_args; 00922 new_event->event_options=event_options; 00923 new_event->run_time=run_time; 00924 new_event->recurring=recurring; 00925 new_event->event_interval=event_interval; 00926 new_event->timing_func=timing_func; 00927 new_event->compensate_for_time_change=compensate_for_time_change; 00928 } 00929 else 00930 return ERROR; 00931 00932 /* add the event to the event list */ 00933 add_event(new_event,event_list,event_list_tail); 00934 00935 return OK; 00936 } 00937 00938 00939 /* reschedule an event in order of execution time */ 00940 void reschedule_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){ 00941 time_t current_time=0L; 00942 time_t (*timingfunc)(void); 00943 00944 log_debug_info(DEBUGL_FUNCTIONS,0,"reschedule_event()\n"); 00945 00946 /* reschedule recurring events... */ 00947 if(event->recurring==TRUE){ 00948 00949 /* use custom timing function */ 00950 if(event->timing_func!=NULL){ 00951 timingfunc=event->timing_func; 00952 event->run_time=(*timingfunc)(); 00953 } 00954 00955 /* normal recurring events */ 00956 else{ 00957 event->run_time=event->run_time+event->event_interval; 00958 time(¤t_time); 00959 if(event->run_time<current_time) 00960 event->run_time=current_time; 00961 } 00962 } 00963 00964 /* add the event to the event list */ 00965 add_event(event,event_list,event_list_tail); 00966 00967 return; 00968 } 00969 00970 00971 /* add an event to list ordered by execution time */ 00972 void add_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){ 00973 timed_event *temp_event=NULL; 00974 timed_event *first_event=NULL; 00975 00976 log_debug_info(DEBUGL_FUNCTIONS,0,"add_event()\n"); 00977 00978 event->next=NULL; 00979 event->prev=NULL; 00980 00981 first_event=*event_list; 00982 00983 /* add the event to the head of the list if there are no other events */ 00984 if(*event_list==NULL){ 00985 *event_list=event; 00986 *event_list_tail=event; 00987 } 00988 00989 /* add event to head of the list if it should be executed first */ 00990 else if(event->run_time < first_event->run_time){ 00991 event->prev=NULL; 00992 (*event_list)->prev=event; 00993 event->next=*event_list; 00994 *event_list=event; 00995 } 00996 00997 /* else place the event according to next execution time */ 00998 else{ 00999 01000 /* start from the end of the list, as new events are likely to be executed in the future, rather than now... */ 01001 for(temp_event=*event_list_tail;temp_event!=NULL;temp_event=temp_event->prev){ 01002 if(event->run_time >= temp_event->run_time){ 01003 event->next=temp_event->next; 01004 event->prev=temp_event; 01005 temp_event->next=event; 01006 if(event->next==NULL) 01007 *event_list_tail=event; 01008 else 01009 event->next->prev=event; 01010 break; 01011 } 01012 else if(temp_event->prev==NULL){ 01013 temp_event->prev=event; 01014 event->next=temp_event; 01015 *event_list=event; 01016 break; 01017 } 01018 } 01019 } 01020 01021 #ifdef USE_EVENT_BROKER 01022 /* send event data to broker */ 01023 broker_timed_event(NEBTYPE_TIMEDEVENT_ADD,NEBFLAG_NONE,NEBATTR_NONE,event,NULL); 01024 #endif 01025 01026 return; 01027 } 01028 01029 01030 01031 /* remove an event from the queue */ 01032 void remove_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){ 01033 timed_event *temp_event=NULL; 01034 01035 log_debug_info(DEBUGL_FUNCTIONS,0,"remove_event()\n"); 01036 01037 #ifdef USE_EVENT_BROKER 01038 /* send event data to broker */ 01039 broker_timed_event(NEBTYPE_TIMEDEVENT_REMOVE,NEBFLAG_NONE,NEBATTR_NONE,event,NULL); 01040 #endif 01041 01042 if(*event_list==NULL) 01043 return; 01044 01045 if(*event_list==event){ 01046 event->prev=NULL; 01047 *event_list=event->next; 01048 if(*event_list==NULL) 01049 *event_list_tail=NULL; 01050 } 01051 01052 else{ 01053 01054 for(temp_event=*event_list;temp_event!=NULL;temp_event=temp_event->next){ 01055 if(temp_event->next==event){ 01056 temp_event->next=temp_event->next->next; 01057 if(temp_event->next==NULL) 01058 *event_list_tail=temp_event; 01059 else 01060 temp_event->next->prev=temp_event; 01061 event->next=NULL; 01062 event->prev=NULL; 01063 break; 01064 } 01065 } 01066 } 01067 01068 01069 return; 01070 } 01071 01072 01073 01074 /* this is the main event handler loop */ 01075 int event_execution_loop(void){ 01076 timed_event *temp_event=NULL; 01077 timed_event sleep_event; 01078 time_t last_time=0L; 01079 time_t current_time=0L; 01080 time_t last_status_update=0L; 01081 int run_event=TRUE; 01082 int nudge_seconds; 01083 host *temp_host=NULL; 01084 service *temp_service=NULL; 01085 struct timespec delay; 01086 pid_t wait_result; 01087 01088 /* make sure gcc3 won't hit here */ 01089 #ifndef GCCTOOOLD 01090 struct timeval start; 01091 #endif 01092 01093 log_debug_info(DEBUGL_FUNCTIONS,0,"event_execution_loop() start\n"); 01094 01095 time(&last_time); 01096 01097 /* initialize fake "sleep" event */ 01098 sleep_event.event_type=EVENT_SLEEP; 01099 sleep_event.run_time=last_time; 01100 sleep_event.recurring=FALSE; 01101 sleep_event.event_interval=0L; 01102 sleep_event.compensate_for_time_change=FALSE; 01103 sleep_event.timing_func=NULL; 01104 sleep_event.event_data=NULL; 01105 sleep_event.event_args=NULL; 01106 sleep_event.event_options=0; 01107 sleep_event.next=NULL; 01108 sleep_event.prev=NULL; 01109 01110 while(1){ 01111 01112 /* make sure gcc3 won't hit here */ 01113 #ifndef GCCTOOOLD 01114 if(event_profiling_enabled) 01115 gettimeofday(&start,NULL); 01116 #endif 01117 01118 /* see if we should exit or restart (a signal was encountered) */ 01119 if(sigshutdown==TRUE || sigrestart==TRUE) 01120 break; 01121 01122 /* if we don't have any events to handle, exit */ 01123 if(event_list_high==NULL && event_list_low==NULL){ 01124 log_debug_info(DEBUGL_EVENTS,0,"There aren't any events that need to be handled! Exiting...\n"); 01125 break; 01126 } 01127 01128 /* get the current time */ 01129 time(¤t_time); 01130 01131 /* hey, wait a second... we traveled back in time! */ 01132 if(current_time<last_time) 01133 compensate_for_system_time_change((unsigned long)last_time,(unsigned long)current_time); 01134 01135 /* else if the time advanced over the specified threshold, try and compensate... */ 01136 else if((current_time-last_time)>=time_change_threshold) 01137 compensate_for_system_time_change((unsigned long)last_time,(unsigned long)current_time); 01138 01139 /* keep track of the last time */ 01140 last_time=current_time; 01141 01142 log_debug_info(DEBUGL_EVENTS,1,"** Event Check Loop\n"); 01143 if(event_list_high!=NULL) 01144 log_debug_info(DEBUGL_EVENTS,1,"Next High Priority Event Time: %s",ctime(&event_list_high->run_time)); 01145 else 01146 log_debug_info(DEBUGL_EVENTS,1,"No high priority events are scheduled...\n"); 01147 if(event_list_low!=NULL) 01148 log_debug_info(DEBUGL_EVENTS,1,"Next Low Priority Event Time: %s",ctime(&event_list_low->run_time)); 01149 else 01150 log_debug_info(DEBUGL_EVENTS,1,"No low priority events are scheduled...\n"); 01151 log_debug_info(DEBUGL_EVENTS,1,"Current/Max Service Checks: %d/%d\n",currently_running_service_checks,max_parallel_service_checks); 01152 01153 /* get rid of terminated child processes (zombies) */ 01154 if(child_processes_fork_twice==FALSE){ 01155 while((wait_result=waitpid(-1,NULL,WNOHANG))>0); 01156 } 01157 01158 /* handle high priority events */ 01159 if(event_list_high!=NULL && (current_time>=event_list_high->run_time)){ 01160 01161 /* remove the first event from the timing loop */ 01162 temp_event=event_list_high; 01163 event_list_high=event_list_high->next; 01164 01165 /* we may have just removed the only item from the list */ 01166 if (event_list_high!=NULL) 01167 event_list_high->prev=NULL; 01168 01169 /* handle the event */ 01170 handle_timed_event(temp_event); 01171 01172 /* reschedule the event if necessary */ 01173 if(temp_event->recurring==TRUE) 01174 reschedule_event(temp_event,&event_list_high,&event_list_high_tail); 01175 01176 /* else free memory associated with the event */ 01177 else 01178 my_free(temp_event); 01179 } 01180 01181 /* 21-09-2010 NOTE MF: 01182 The logic on low priority events just as host and service checks work liks this: 01183 Set run_event=TRUE on looping start, check if next event is a serviecheck. If matched, 01184 check for several things, most important for disabled checks. If those are disabled, 01185 set run_event=FALSE (this flag will be checked at the end). The servicecheck event 01186 will be removed from the eventlist. 01187 Same goes for the hostcheck events, and afterwards, run_event is checked and no matter 01188 if service or host check event, it gets executed as a timed event, if run_event==TRUE. 01189 01190 Previous code (21-09-2010) had a logical AND operation, servicecheck and hostcheck events 01191 could have been tested within one looping. If servicecheck was disabled, run_event=FALSE, 01192 and removed from event queue resulted in next event = hostcheck, which was matched by the 01193 2nd IF - also having run_event set to FALSE, causing the hostcheck being skipped too. 01194 By changing this to a logical OR operation, IF ... ELSE IF ..., only one check can be 01195 matched throughout a single looping and run_event is responsible for only one event at a 01196 time - service OR host check event. 01197 */ 01198 01199 /* handle low priority events */ 01200 else if(event_list_low!=NULL && (current_time>=event_list_low->run_time)){ 01201 01202 /* default action is to execute the event */ 01203 run_event=TRUE; 01204 nudge_seconds=0; 01205 01206 /* run a few checks before executing a service check... */ 01207 if(event_list_low->event_type==EVENT_SERVICE_CHECK){ 01208 01209 temp_service=(service *)event_list_low->event_data; 01210 01211 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Run a few checks before executing a service check for '%s'.\n", temp_service->description); 01212 01213 /* don't run a service check if we're already maxed out on the number of parallel service checks... */ 01214 if(max_parallel_service_checks!=0 && (currently_running_service_checks >= max_parallel_service_checks)){ 01215 01216 /* Move it at least 5 seconds (to overcome the current peak), with a random 10 seconds (to spread the load) */ 01217 nudge_seconds=5+(rand() % 10); 01218 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,0,"**WARNING** Max concurrent service checks (%d) has been reached! Nudging %s:%s by %d seconds...\n",max_parallel_service_checks, temp_service->host_name, temp_service->description, nudge_seconds); 01219 01220 logit(NSLOG_RUNTIME_WARNING,TRUE,"\tMax concurrent service checks (%d) has been reached. Nudging %s:%s by %d seconds...\n",max_parallel_service_checks, temp_service->host_name, temp_service->description, nudge_seconds); 01221 run_event=FALSE; 01222 } 01223 01224 /* don't run a service check if active checks are disabled */ 01225 if(execute_service_checks==FALSE){ 01226 01227 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"We're not executing service checks right now, so we'll skip this event.\n"); 01228 01229 run_event=FALSE; 01230 } 01231 01232 /* forced checks override normal check logic */ 01233 if((temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)) 01234 run_event=TRUE; 01235 01236 /* reschedule the check if we can't run it now */ 01237 if(run_event==FALSE){ 01238 01239 /* remove the service check from the event queue and reschedule it for a later time */ 01240 /* 12/20/05 since event was not executed, it needs to be remove()'ed to maintain sync with event broker modules */ 01241 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Skip event, removing service '%s' from list.\n", temp_service->description); 01242 temp_event=event_list_low; 01243 remove_event(temp_event,&event_list_low,&event_list_low_tail); 01244 /* 01245 event_list_low=event_list_low->next; 01246 */ 01247 if(nudge_seconds) { 01248 /* We nudge the next check time when it is due to too many concurrent service checks */ 01249 temp_service->next_check=(time_t)(temp_service->next_check+nudge_seconds); 01250 } 01251 else { 01252 /* Otherwise reschedule (TODO: This should be smarter as it doesn't consider its timeperiod) */ 01253 if(temp_service->state_type==SOFT_STATE && temp_service->current_state!=STATE_OK) 01254 temp_service->next_check=(time_t)(temp_service->next_check+(temp_service->retry_interval*interval_length)); 01255 else 01256 temp_service->next_check=(time_t)(temp_service->next_check+(temp_service->check_interval*interval_length)); 01257 } 01258 01259 temp_event->run_time=temp_service->next_check; 01260 reschedule_event(temp_event,&event_list_low,&event_list_low_tail); 01261 update_service_status(temp_service,FALSE); 01262 01263 run_event=FALSE; 01264 } 01265 01266 } 01267 01268 /* run a few checks before executing a host check... */ 01269 else if(event_list_low->event_type==EVENT_HOST_CHECK){ 01270 01271 temp_host=(host *)event_list_low->event_data; 01272 01273 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Run a few checks before executing a host check for '%s'.\n", temp_host->name); 01274 01275 /* don't run a host check if active checks are disabled */ 01276 if(execute_host_checks==FALSE){ 01277 01278 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"We're not executing host checks right now, so we'll skip this event.\n"); 01279 01280 run_event=FALSE; 01281 } 01282 01283 /* forced checks override normal check logic */ 01284 if((temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)) 01285 run_event=TRUE; 01286 01287 /* reschedule the host check if we can't run it right now */ 01288 if(run_event==FALSE){ 01289 01290 /* remove the host check from the event queue and reschedule it for a later time */ 01291 /* 12/20/05 since event was not executed, it needs to be remove()'ed to maintain sync with event broker modules */ 01292 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Skip event, removing host '%s' from list.\n", temp_host->name); 01293 temp_event=event_list_low; 01294 remove_event(temp_event,&event_list_low,&event_list_low_tail); 01295 /* 01296 event_list_low=event_list_low->next; 01297 */ 01298 if(temp_host->state_type==SOFT_STATE && temp_host->current_state!=STATE_OK) 01299 temp_host->next_check=(time_t)(temp_host->next_check+(temp_host->retry_interval*interval_length)); 01300 else 01301 temp_host->next_check=(time_t)(temp_host->next_check+(temp_host->check_interval*interval_length)); 01302 01303 temp_event->run_time=temp_host->next_check; 01304 reschedule_event(temp_event,&event_list_low,&event_list_low_tail); 01305 update_host_status(temp_host,FALSE); 01306 01307 run_event=FALSE; 01308 } 01309 } 01310 01311 /* run the event */ 01312 if(run_event==TRUE){ 01313 01314 /* remove the first event from the timing loop */ 01315 temp_event=event_list_low; 01316 event_list_low=event_list_low->next; 01317 /* we may have just removed the only item from the list */ 01318 if(event_list_low!=NULL) 01319 event_list_low->prev=NULL; 01320 01321 log_debug_info(DEBUGL_EVENTS,1,"Running event...\n"); 01322 01323 # /* handle the event */ 01324 handle_timed_event(temp_event); 01325 01326 /* reschedule the event if necessary */ 01327 if(temp_event->recurring==TRUE) 01328 reschedule_event(temp_event,&event_list_low,&event_list_low_tail); 01329 01330 /* else free memory associated with the event */ 01331 else 01332 my_free(temp_event); 01333 } 01334 01335 } 01336 01337 /* we don't have anything to do at this moment in time... */ 01338 else if((event_list_high==NULL || (current_time<event_list_high->run_time)) && (event_list_low==NULL || (current_time<event_list_low->run_time))){ 01339 01340 log_debug_info(DEBUGL_EVENTS,2,"No events to execute at the moment. Idling for a bit...\n"); 01341 01342 /* check for external commands if we're supposed to check as often as possible */ 01343 if(command_check_interval==-1) 01344 check_for_external_commands(); 01345 01346 /* set time to sleep so we don't hog the CPU... */ 01347 #ifdef USE_NANOSLEEP 01348 delay.tv_sec=(time_t)sleep_time; 01349 delay.tv_nsec=(long)((sleep_time-(double)delay.tv_sec)*1000000000); 01350 #else 01351 delay.tv_sec=(time_t)sleep_time; 01352 if(delay.tv_sec==0L) 01353 delay.tv_sec=1; 01354 delay.tv_nsec=0L; 01355 #endif 01356 01357 #ifdef USE_EVENT_BROKER 01358 /* populate fake "sleep" event */ 01359 sleep_event.run_time=current_time; 01360 sleep_event.event_data=(void *)&delay; 01361 01362 /* send event data to broker */ 01363 broker_timed_event(NEBTYPE_TIMEDEVENT_SLEEP,NEBFLAG_NONE,NEBATTR_NONE,&sleep_event,NULL); 01364 #endif 01365 01366 /* wait a while so we don't hog the CPU... */ 01367 #ifdef USE_NANOSLEEP 01368 nanosleep(&delay,NULL); 01369 #else 01370 sleep((unsigned int)delay.tv_sec); 01371 #endif 01372 } 01373 01374 /* update status information occassionally - NagVis watches the NDOUtils DB to see if Icinga is alive */ 01375 if((unsigned long)(current_time-last_status_update)>5){ 01376 last_status_update=current_time; 01377 update_program_status(FALSE); 01378 } 01379 01380 /* make sure gcc3 won't hit here */ 01381 #ifndef GCCTOOOLD 01382 if(event_profiling_enabled) 01383 profiler_update(EVENT_LOOP_COMPLETION, start); 01384 #endif 01385 01386 } 01387 01388 log_debug_info(DEBUGL_FUNCTIONS,0,"event_execution_loop() end\n"); 01389 01390 return OK; 01391 } 01392 01393 01394 01395 /* handles a timed event */ 01396 int handle_timed_event(timed_event *event){ 01397 host *temp_host=NULL; 01398 service *temp_service=NULL; 01399 void (*userfunc)(void *); 01400 struct timeval tv; 01401 double latency=0.0; 01402 /* make sure gcc3 won't hit here */ 01403 #ifndef GCCTOOOLD 01404 struct timeval start; 01405 gettimeofday(&start,NULL); 01406 #endif 01407 01408 log_debug_info(DEBUGL_FUNCTIONS,0,"handle_timed_event() start\n"); 01409 01410 #ifdef USE_EVENT_BROKER 01411 /* send event data to broker */ 01412 broker_timed_event(NEBTYPE_TIMEDEVENT_EXECUTE,NEBFLAG_NONE,NEBATTR_NONE,event,NULL); 01413 #endif 01414 01415 log_debug_info(DEBUGL_EVENTS,0,"** Timed Event ** Type: %d, Run Time: %s",event->event_type,ctime(&event->run_time)); 01416 01417 /* how should we handle the event? */ 01418 switch(event->event_type){ 01419 01420 case EVENT_SERVICE_CHECK: 01421 01422 temp_service=(service *)event->event_data; 01423 01424 /* get check latency */ 01425 gettimeofday(&tv,NULL); 01426 latency=(double)((double)(tv.tv_sec-event->run_time)+(double)(tv.tv_usec/1000)/1000.0); 01427 01428 log_debug_info(DEBUGL_EVENTS,0,"** Service Check Event ==> Host: '%s', Service: '%s', Options: %d, Latency: %f sec\n",temp_service->host_name,temp_service->description,event->event_options,latency); 01429 01430 /* run the service check */ 01431 temp_service=(service *)event->event_data; 01432 run_scheduled_service_check(temp_service,event->event_options,latency); 01433 break; 01434 01435 case EVENT_HOST_CHECK: 01436 01437 temp_host=(host *)event->event_data; 01438 01439 /* get check latency */ 01440 gettimeofday(&tv,NULL); 01441 latency=(double)((double)(tv.tv_sec-event->run_time)+(double)(tv.tv_usec/1000)/1000.0); 01442 01443 log_debug_info(DEBUGL_EVENTS,0,"** Host Check Event ==> Host: '%s', Options: %d, Latency: %f sec\n",temp_host->name,event->event_options,latency); 01444 01445 /* run the host check */ 01446 temp_host=(host *)event->event_data; 01447 perform_scheduled_host_check(temp_host,event->event_options,latency); 01448 break; 01449 01450 case EVENT_COMMAND_CHECK: 01451 01452 log_debug_info(DEBUGL_EVENTS,0,"** External Command Check Event\n"); 01453 01454 /* check for external commands */ 01455 check_for_external_commands(); 01456 break; 01457 01458 case EVENT_LOG_ROTATION: 01459 01460 log_debug_info(DEBUGL_EVENTS,0,"** Log File Rotation Event\n"); 01461 01462 /* rotate the log file */ 01463 rotate_log_file(event->run_time); 01464 break; 01465 01466 case EVENT_PROGRAM_SHUTDOWN: 01467 01468 log_debug_info(DEBUGL_EVENTS,0,"** Program Shutdown Event\n"); 01469 01470 /* set the shutdown flag */ 01471 sigshutdown=TRUE; 01472 01473 /* log the shutdown */ 01474 logit(NSLOG_PROCESS_INFO,TRUE,"PROGRAM_SHUTDOWN event encountered, shutting down...\n"); 01475 break; 01476 01477 case EVENT_PROGRAM_RESTART: 01478 01479 log_debug_info(DEBUGL_EVENTS,0,"** Program Restart Event\n"); 01480 01481 /* set the restart flag */ 01482 sigrestart=TRUE; 01483 01484 /* log the restart */ 01485 logit(NSLOG_PROCESS_INFO,TRUE,"PROGRAM_RESTART event encountered, restarting...\n"); 01486 break; 01487 01488 case EVENT_CHECK_REAPER: 01489 01490 log_debug_info(DEBUGL_EVENTS,0,"** Check Result Reaper\n"); 01491 01492 /* reap host and service check results */ 01493 reap_check_results(); 01494 break; 01495 01496 case EVENT_ORPHAN_CHECK: 01497 01498 log_debug_info(DEBUGL_EVENTS,0,"** Orphaned Host and Service Check Event\n"); 01499 01500 /* check for orphaned hosts and services */ 01501 if(check_orphaned_hosts==TRUE) 01502 check_for_orphaned_hosts(); 01503 if(check_orphaned_services==TRUE) 01504 check_for_orphaned_services(); 01505 break; 01506 01507 case EVENT_RETENTION_SAVE: 01508 01509 log_debug_info(DEBUGL_EVENTS,0,"** Retention Data Save Event\n"); 01510 01511 /* save state retention data */ 01512 save_state_information(TRUE); 01513 break; 01514 01515 case EVENT_STATUS_SAVE: 01516 01517 log_debug_info(DEBUGL_EVENTS,0,"** Status Data Save Event\n"); 01518 01519 /* save all status data (program, host, and service) */ 01520 update_all_status_data(); 01521 break; 01522 01523 case EVENT_SCHEDULED_DOWNTIME: 01524 01525 log_debug_info(DEBUGL_EVENTS,0,"** Scheduled Downtime Event\n"); 01526 01527 /* process scheduled downtime info */ 01528 if(event->event_data){ 01529 handle_scheduled_downtime_by_id(*(unsigned long *)event->event_data); 01530 free(event->event_data); 01531 event->event_data=NULL; 01532 } 01533 break; 01534 01535 case EVENT_SFRESHNESS_CHECK: 01536 01537 log_debug_info(DEBUGL_EVENTS,0,"** Service Result Freshness Check Event\n"); 01538 01539 /* check service result freshness */ 01540 check_service_result_freshness(); 01541 break; 01542 01543 case EVENT_HFRESHNESS_CHECK: 01544 01545 log_debug_info(DEBUGL_EVENTS,0,"** Host Result Freshness Check Event\n"); 01546 01547 /* check host result freshness */ 01548 check_host_result_freshness(); 01549 break; 01550 01551 case EVENT_EXPIRE_DOWNTIME: 01552 01553 log_debug_info(DEBUGL_EVENTS,0,"** Expire Downtime Event\n"); 01554 01555 /* check for expired scheduled downtime entries */ 01556 check_for_expired_downtime(); 01557 break; 01558 01559 case EVENT_RESCHEDULE_CHECKS: 01560 01561 /* adjust scheduling of host and service checks */ 01562 log_debug_info(DEBUGL_EVENTS,0,"** Reschedule Checks Event\n"); 01563 01564 adjust_check_scheduling(); 01565 break; 01566 01567 case EVENT_EXPIRE_COMMENT: 01568 01569 log_debug_info(DEBUGL_EVENTS,0,"** Expire Comment Event\n"); 01570 01571 /* check for expired comment */ 01572 check_for_expired_comment((unsigned long)event->event_data); 01573 break; 01574 01575 case EVENT_USER_FUNCTION: 01576 01577 log_debug_info(DEBUGL_EVENTS,0,"** User Function Event\n"); 01578 01579 /* run a user-defined function */ 01580 if(event->event_data!=NULL){ 01581 userfunc=event->event_data; 01582 (*userfunc)(event->event_args); 01583 } 01584 break; 01585 01586 default: 01587 01588 break; 01589 } 01590 01591 log_debug_info(DEBUGL_FUNCTIONS,0,"handle_timed_event() end\n"); 01592 01593 /* make sure gcc3 won't hit here */ 01594 #ifndef GCCTOOOLD 01595 if(event_profiling_enabled) 01596 profiler_update(event->event_type,start); 01597 #endif 01598 01599 return OK; 01600 } 01601 01602 01603 01604 /* adjusts scheduling of host and service checks */ 01605 void adjust_check_scheduling(void){ 01606 timed_event *temp_event=NULL; 01607 service *temp_service=NULL; 01608 host *temp_host=NULL; 01609 double projected_host_check_overhead=0.1; 01610 double projected_service_check_overhead=0.1; 01611 time_t current_time=0L; 01612 time_t first_window_time=0L; 01613 time_t last_window_time=0L; 01614 time_t last_check_time=0L; 01615 time_t new_run_time=0L; 01616 int total_checks=0; 01617 int current_check=0; 01618 double inter_check_delay=0.0; 01619 double current_icd_offset=0.0; 01620 double total_check_exec_time=0.0; 01621 double last_check_exec_time=0.0; 01622 int adjust_scheduling=FALSE; 01623 double exec_time_factor=0.0; 01624 double current_exec_time=0.0; 01625 double current_exec_time_offset=0.0; 01626 double new_run_time_offset=0.0; 01627 01628 01629 log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_check_scheduling() start\n"); 01630 01631 /* TODO: 01632 - Track host check overhead on a per-host basis 01633 - Figure out how to calculate service check overhead 01634 */ 01635 01636 /* determine our adjustment window */ 01637 time(¤t_time); 01638 first_window_time=current_time; 01639 last_window_time=first_window_time+auto_rescheduling_window; 01640 01641 /* get current scheduling data */ 01642 for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){ 01643 01644 /* skip events outside of our current window */ 01645 if(temp_event->run_time<=first_window_time) 01646 continue; 01647 if(temp_event->run_time>last_window_time) 01648 break; 01649 01650 if(temp_event->event_type==EVENT_HOST_CHECK){ 01651 01652 if((temp_host=(host *)temp_event->event_data)==NULL) 01653 continue; 01654 01655 /* ignore forced checks */ 01656 if(temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION) 01657 continue; 01658 01659 /* does the last check "bump" into this one? */ 01660 if((unsigned long)(last_check_time+last_check_exec_time)>temp_event->run_time) 01661 adjust_scheduling=TRUE; 01662 01663 last_check_time=temp_event->run_time; 01664 01665 /* calculate time needed to perform check */ 01666 /* NOTE: host check execution time is not taken into account, as scheduled host checks are run in parallel */ 01667 last_check_exec_time=projected_host_check_overhead; 01668 total_check_exec_time+=last_check_exec_time; 01669 } 01670 01671 else if(temp_event->event_type==EVENT_SERVICE_CHECK){ 01672 01673 if((temp_service=(service *)temp_event->event_data)==NULL) 01674 continue; 01675 01676 /* ignore forced checks */ 01677 if(temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION) 01678 continue; 01679 01680 /* does the last check "bump" into this one? */ 01681 if((unsigned long)(last_check_time+last_check_exec_time)>temp_event->run_time) 01682 adjust_scheduling=TRUE; 01683 01684 last_check_time=temp_event->run_time; 01685 01686 /* calculate time needed to perform check */ 01687 /* NOTE: service check execution time is not taken into account, as service checks are run in parallel */ 01688 last_check_exec_time=projected_service_check_overhead; 01689 total_check_exec_time+=last_check_exec_time; 01690 } 01691 01692 else 01693 continue; 01694 01695 total_checks++; 01696 } 01697 01698 01699 /* nothing to do... */ 01700 if(total_checks==0 || adjust_scheduling==FALSE){ 01701 01702 /* 01703 printf("\n\n"); 01704 printf("NOTHING TO DO!\n"); 01705 printf("# CHECKS: %d\n",total_checks); 01706 printf("WINDOW TIME: %d\n",auto_rescheduling_window); 01707 printf("EXEC TIME: %.3f\n",total_check_exec_time); 01708 */ 01709 01710 return; 01711 } 01712 01713 if((unsigned long)total_check_exec_time>auto_rescheduling_window){ 01714 inter_check_delay=0.0; 01715 exec_time_factor=(double)((double)auto_rescheduling_window/total_check_exec_time); 01716 } 01717 else{ 01718 inter_check_delay=(double)((((double)auto_rescheduling_window)-total_check_exec_time)/(double)(total_checks*1.0)); 01719 exec_time_factor=1.0; 01720 } 01721 01722 /* 01723 printf("\n\n"); 01724 printf("TOTAL CHECKS: %d\n",total_checks); 01725 printf("WINDOW TIME: %d\n",auto_rescheduling_window); 01726 printf("EXEC TIME: %.3f\n",total_check_exec_time); 01727 printf("ICD: %.3f\n",inter_check_delay); 01728 printf("EXEC FACTOR: %.3f\n",exec_time_factor); 01729 */ 01730 01731 /* adjust check scheduling */ 01732 current_icd_offset=(inter_check_delay/2.0); 01733 for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){ 01734 01735 /* skip events outside of our current window */ 01736 if(temp_event->run_time<=first_window_time) 01737 continue; 01738 if(temp_event->run_time>last_window_time) 01739 break; 01740 01741 if(temp_event->event_type==EVENT_HOST_CHECK){ 01742 01743 if((temp_host=(host *)temp_event->event_data)==NULL) 01744 continue; 01745 01746 /* ignore forced checks */ 01747 if(temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION) 01748 continue; 01749 01750 current_exec_time=((temp_host->execution_time+projected_host_check_overhead)*exec_time_factor); 01751 } 01752 01753 else if(temp_event->event_type==EVENT_SERVICE_CHECK){ 01754 01755 if((temp_service=(service *)temp_event->event_data)==NULL) 01756 continue; 01757 01758 /* ignore forced checks */ 01759 if(temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION) 01760 continue; 01761 01762 /* NOTE: service check execution time is not taken into account, as service checks are run in parallel */ 01763 current_exec_time=(projected_service_check_overhead*exec_time_factor); 01764 } 01765 01766 else 01767 continue; 01768 01769 current_check++; 01770 new_run_time_offset=current_exec_time_offset+current_icd_offset; 01771 new_run_time=(time_t)(first_window_time+(unsigned long)new_run_time_offset); 01772 01773 /* 01774 printf(" CURRENT CHECK #: %d\n",current_check); 01775 printf(" CURRENT ICD OFFSET: %.3f\n",current_icd_offset); 01776 printf(" CURRENT EXEC TIME: %.3f\n",current_exec_time); 01777 printf(" CURRENT EXEC OFFSET: %.3f\n",current_exec_time_offset); 01778 printf(" NEW RUN TIME: %lu\n",new_run_time); 01779 */ 01780 01781 if(temp_event->event_type==EVENT_HOST_CHECK){ 01782 temp_event->run_time=new_run_time; 01783 temp_host->next_check=new_run_time; 01784 update_host_status(temp_host,FALSE); 01785 } 01786 else{ 01787 temp_event->run_time=new_run_time; 01788 temp_service->next_check=new_run_time; 01789 update_service_status(temp_service,FALSE); 01790 } 01791 01792 current_icd_offset+=inter_check_delay; 01793 current_exec_time_offset+=current_exec_time; 01794 } 01795 01796 /* resort event list (some events may be out of order at this point) */ 01797 resort_event_list(&event_list_low,&event_list_low_tail); 01798 01799 log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_check_scheduling() end\n"); 01800 01801 return; 01802 } 01803 01804 01805 01806 /* attempts to compensate for a change in the system time */ 01807 void compensate_for_system_time_change(unsigned long last_time, unsigned long current_time){ 01808 unsigned long time_difference=0L; 01809 timed_event *temp_event=NULL; 01810 service *temp_service=NULL; 01811 host *temp_host=NULL; 01812 int days=0; 01813 int hours=0; 01814 int minutes=0; 01815 int seconds=0; 01816 time_t (*timingfunc)(void); 01817 01818 01819 log_debug_info(DEBUGL_FUNCTIONS,0,"compensate_for_system_time_change() start\n"); 01820 01821 /* we moved back in time... */ 01822 if(last_time>current_time){ 01823 time_difference=last_time-current_time; 01824 get_time_breakdown(time_difference,&days,&hours,&minutes,&seconds); 01825 log_debug_info(DEBUGL_EVENTS,0,"Detected a backwards time change of %dd %dh %dm %ds.\n",days,hours,minutes,seconds); 01826 } 01827 01828 /* we moved into the future... */ 01829 else{ 01830 time_difference=current_time-last_time; 01831 get_time_breakdown(time_difference,&days,&hours,&minutes,&seconds); 01832 log_debug_info(DEBUGL_EVENTS,0,"Detected a forwards time change of %dd %dh %dm %ds.\n",days,hours,minutes,seconds); 01833 } 01834 01835 /* log the time change */ 01836 logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_WARNING,TRUE,"Warning: A system time change of %dd %dh %dm %ds (%s in time) has been detected. Compensating...\n",days,hours,minutes,seconds,(last_time>current_time)?"backwards":"forwards"); 01837 01838 /* adjust the next run time for all high priority timed events */ 01839 for(temp_event=event_list_high;temp_event!=NULL;temp_event=temp_event->next){ 01840 01841 /* skip special events that occur at specific times... */ 01842 if(temp_event->compensate_for_time_change==FALSE) 01843 continue; 01844 01845 /* use custom timing function */ 01846 if(temp_event->timing_func!=NULL){ 01847 timingfunc=temp_event->timing_func; 01848 temp_event->run_time=(*timingfunc)(); 01849 } 01850 01851 /* else use standard adjustment */ 01852 else 01853 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_event->run_time); 01854 } 01855 01856 /* resort event list (some events may be out of order at this point) */ 01857 resort_event_list(&event_list_high,&event_list_high_tail); 01858 01859 /* adjust the next run time for all low priority timed events */ 01860 for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){ 01861 01862 /* skip special events that occur at specific times... */ 01863 if(temp_event->compensate_for_time_change==FALSE) 01864 continue; 01865 01866 /* use custom timing function */ 01867 if(temp_event->timing_func!=NULL){ 01868 timingfunc=temp_event->timing_func; 01869 temp_event->run_time=(*timingfunc)(); 01870 } 01871 01872 /* else use standard adjustment */ 01873 else 01874 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_event->run_time); 01875 } 01876 01877 /* resort event list (some events may be out of order at this point) */ 01878 resort_event_list(&event_list_low,&event_list_low_tail); 01879 01880 /* adjust service timestamps */ 01881 for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){ 01882 01883 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_notification); 01884 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_check); 01885 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->next_check); 01886 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_state_change); 01887 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_hard_state_change); 01888 01889 /* recalculate next re-notification time */ 01890 temp_service->next_notification=get_next_service_notification_time(temp_service,temp_service->last_notification); 01891 01892 /* update the status data */ 01893 update_service_status(temp_service,FALSE); 01894 } 01895 01896 /* adjust host timestamps */ 01897 for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){ 01898 01899 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_host_notification); 01900 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_check); 01901 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->next_check); 01902 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_state_change); 01903 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_hard_state_change); 01904 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_state_history_update); 01905 01906 /* recalculate next re-notification time */ 01907 temp_host->next_host_notification=get_next_host_notification_time(temp_host,temp_host->last_host_notification); 01908 01909 /* update the status data */ 01910 update_host_status(temp_host,FALSE); 01911 } 01912 01913 /* adjust program timestamps */ 01914 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&program_start); 01915 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&event_start); 01916 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&last_command_check); 01917 01918 /* update the status data */ 01919 update_program_status(FALSE); 01920 01921 return; 01922 } 01923 01924 01925 01926 /* resorts an event list by event execution time - needed when compensating for system time changes */ 01927 void resort_event_list(timed_event **event_list, timed_event **event_list_tail){ 01928 timed_event *temp_event_list=NULL; 01929 timed_event *temp_event=NULL; 01930 timed_event *next_event=NULL; 01931 01932 log_debug_info(DEBUGL_FUNCTIONS,0,"resort_event_list()\n"); 01933 01934 /* move current event list to temp list */ 01935 temp_event_list=*event_list; 01936 *event_list=NULL; 01937 01938 /* move all events to the new event list */ 01939 for(temp_event=temp_event_list;temp_event!=NULL;temp_event=next_event){ 01940 next_event=temp_event->next; 01941 01942 /* add the event to the newly created event list so it will be resorted */ 01943 temp_event->next=NULL; 01944 temp_event->prev=NULL; 01945 add_event(temp_event,event_list,event_list_tail); 01946 } 01947 01948 return; 01949 } 01950 01951 01952 01953 /* adjusts a timestamp variable in accordance with a system time change */ 01954 void adjust_timestamp_for_time_change(time_t last_time, time_t current_time, unsigned long time_difference, time_t *ts){ 01955 01956 log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_timestamp_for_time_change()\n"); 01957 01958 /* we shouldn't do anything with epoch values */ 01959 if(*ts==(time_t)0) 01960 return; 01961 01962 /* we moved back in time... */ 01963 if(last_time>current_time){ 01964 01965 /* we can't precede the UNIX epoch */ 01966 if(time_difference>(unsigned long)*ts) 01967 *ts=(time_t)0; 01968 else 01969 *ts=(time_t)(*ts-time_difference); 01970 } 01971 01972 /* we moved into the future... */ 01973 else 01974 *ts=(time_t)(*ts+time_difference); 01975 01976 return; 01977 }