1# -*- cperl -*- 2# Copyright (c) 2006 MySQL AB, 2008 Sun Microsystems, Inc. 3# Use is subject to license terms. 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License, version 2.0, 7# as published by the Free Software Foundation. 8# 9# This program is also distributed with certain software (including 10# but not limited to OpenSSL) that is licensed under separate terms, 11# as designated in a particular file or component or in included license 12# documentation. The authors of MySQL hereby grant you an additional 13# permission to link the program and your derivative works with the 14# separately licensed software that they have included with MySQL. 15# 16# This program is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19# GNU General Public License, version 2.0, for more details. 20# 21# You should have received a copy of the GNU General Public License 22# along with this program; if not, write to the Free Software 23# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25# This is a library file used by the Perl version of mysql-test-run, 26# and is part of the translation of the Bourne shell script with the 27# same name. 28 29use strict; 30 31# Private IM-related operations. 32 33sub mtr_im_kill_process ($$$$); 34sub mtr_im_load_pids ($); 35sub mtr_im_terminate ($); 36sub mtr_im_check_alive ($); 37sub mtr_im_check_main_alive ($); 38sub mtr_im_check_angel_alive ($); 39sub mtr_im_check_mysqlds_alive ($); 40sub mtr_im_check_mysqld_alive ($); 41sub mtr_im_cleanup ($); 42sub mtr_im_rm_file ($); 43sub mtr_im_errlog ($); 44sub mtr_im_kill ($); 45sub mtr_im_wait_for_connection ($$$); 46sub mtr_im_wait_for_mysqld($$$); 47 48# Public IM-related operations. 49 50sub mtr_im_start ($$); 51sub mtr_im_stop ($); 52 53############################################################################## 54# 55# Private operations. 56# 57############################################################################## 58 59sub mtr_im_kill_process ($$$$) { 60 my $pid_lst= shift; 61 my $signal= shift; 62 my $total_retries= shift; 63 my $timeout= shift; 64 65 my %pids; 66 67 foreach my $pid ( @{$pid_lst} ) 68 { 69 $pids{$pid}= 1; 70 } 71 72 for ( my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt ) 73 { 74 foreach my $pid ( keys %pids ) 75 { 76 mtr_debug("Sending $signal to $pid..."); 77 78 kill($signal, $pid); 79 80 unless ( kill (0, $pid) ) 81 { 82 mtr_debug("Process $pid died."); 83 delete $pids{$pid}; 84 } 85 } 86 87 return if scalar keys %pids == 0; 88 89 mtr_debug("Sleeping $timeout second(s) waiting for processes to die..."); 90 91 sleep($timeout); 92 } 93 94 mtr_debug("Process(es) " . 95 join(' ', keys %pids) . 96 " is still alive after $total_retries " . 97 "of sending signal $signal."); 98} 99 100########################################################################### 101 102sub mtr_im_load_pids($) { 103 my $im= shift; 104 105 mtr_debug("Loading PID files..."); 106 107 # Obtain mysqld-process pids. 108 109 my $instances = $im->{'instances'}; 110 111 for ( my $idx= 0; $idx < 2; ++$idx ) 112 { 113 mtr_debug("IM-guarded mysqld[$idx] PID file: '" . 114 $instances->[$idx]->{'path_pid'} . "'."); 115 116 my $mysqld_pid; 117 118 if ( -r $instances->[$idx]->{'path_pid'} ) 119 { 120 $mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'}); 121 mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid."); 122 } 123 else 124 { 125 $mysqld_pid= undef; 126 mtr_debug("IM-guarded mysqld[$idx]: no PID file."); 127 } 128 129 $instances->[$idx]->{'pid'}= $mysqld_pid; 130 } 131 132 # Re-read Instance Manager PIDs from the file, since during tests Instance 133 # Manager could have been restarted, so its PIDs could have been changed. 134 135 # - IM-main 136 137 mtr_debug("IM-main PID file: '$im->{path_pid}'."); 138 139 if ( -f $im->{'path_pid'} ) 140 { 141 $im->{'pid'} = 142 mtr_get_pid_from_file($im->{'path_pid'}); 143 144 mtr_debug("IM-main PID: $im->{pid}."); 145 } 146 else 147 { 148 mtr_debug("IM-main: no PID file."); 149 $im->{'pid'}= undef; 150 } 151 152 # - IM-angel 153 154 mtr_debug("IM-angel PID file: '$im->{path_angel_pid}'."); 155 156 if ( -f $im->{'path_angel_pid'} ) 157 { 158 $im->{'angel_pid'} = 159 mtr_get_pid_from_file($im->{'path_angel_pid'}); 160 161 mtr_debug("IM-angel PID: $im->{'angel_pid'}."); 162 } 163 else 164 { 165 mtr_debug("IM-angel: no PID file."); 166 $im->{'angel_pid'} = undef; 167 } 168} 169 170########################################################################### 171 172sub mtr_im_terminate($) { 173 my $im= shift; 174 175 # Load pids from pid-files. We should do it first of all, because IM deletes 176 # them on shutdown. 177 178 mtr_im_load_pids($im); 179 180 mtr_debug("Shutting Instance Manager down..."); 181 182 # Ignoring SIGCHLD so that all children could rest in peace. 183 184 start_reap_all(); 185 186 # Send SIGTERM to IM-main. 187 188 if ( defined $im->{'pid'} ) 189 { 190 mtr_debug("IM-main pid: $im->{pid}."); 191 mtr_debug("Stopping IM-main..."); 192 193 mtr_im_kill_process([ $im->{'pid'} ], 'TERM', 10, 1); 194 } 195 else 196 { 197 mtr_debug("IM-main pid: n/a."); 198 } 199 200 # If IM-angel was alive, wait for it to die. 201 202 if ( defined $im->{'angel_pid'} ) 203 { 204 mtr_debug("IM-angel pid: $im->{'angel_pid'}."); 205 mtr_debug("Waiting for IM-angel to die..."); 206 207 my $total_attempts= 10; 208 209 for ( my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt ) 210 { 211 unless ( kill (0, $im->{'angel_pid'}) ) 212 { 213 mtr_debug("IM-angel died."); 214 last; 215 } 216 217 sleep(1); 218 } 219 } 220 else 221 { 222 mtr_debug("IM-angel pid: n/a."); 223 } 224 225 stop_reap_all(); 226 227 # Re-load PIDs. 228 229 mtr_im_load_pids($im); 230} 231 232########################################################################### 233 234sub mtr_im_check_alive($) { 235 my $im= shift; 236 237 mtr_debug("Checking whether IM-components are alive..."); 238 239 return 1 if mtr_im_check_main_alive($im); 240 241 return 1 if mtr_im_check_angel_alive($im); 242 243 return 1 if mtr_im_check_mysqlds_alive($im); 244 245 return 0; 246} 247 248########################################################################### 249 250sub mtr_im_check_main_alive($) { 251 my $im= shift; 252 253 # Check that the process, that we know to be IM's, is dead. 254 255 if ( defined $im->{'pid'} ) 256 { 257 if ( kill (0, $im->{'pid'}) ) 258 { 259 mtr_debug("IM-main (PID: $im->{pid}) is alive."); 260 return 1; 261 } 262 else 263 { 264 mtr_debug("IM-main (PID: $im->{pid}) is dead."); 265 } 266 } 267 else 268 { 269 mtr_debug("No PID file for IM-main."); 270 } 271 272 # Check that IM does not accept client connections. 273 274 if ( mtr_ping_port($im->{'port'}) ) 275 { 276 mtr_debug("IM-main (port: $im->{port}) " . 277 "is accepting connections."); 278 279 mtr_im_errlog("IM-main is accepting connections on port " . 280 "$im->{port}, but there is no " . 281 "process information."); 282 return 1; 283 } 284 else 285 { 286 mtr_debug("IM-main (port: $im->{port}) " . 287 "does not accept connections."); 288 return 0; 289 } 290} 291 292########################################################################### 293 294sub mtr_im_check_angel_alive($) { 295 my $im= shift; 296 297 # Check that the process, that we know to be the Angel, is dead. 298 299 if ( defined $im->{'angel_pid'} ) 300 { 301 if ( kill (0, $im->{'angel_pid'}) ) 302 { 303 mtr_debug("IM-angel (PID: $im->{angel_pid}) is alive."); 304 return 1; 305 } 306 else 307 { 308 mtr_debug("IM-angel (PID: $im->{angel_pid}) is dead."); 309 return 0; 310 } 311 } 312 else 313 { 314 mtr_debug("No PID file for IM-angel."); 315 return 0; 316 } 317} 318 319########################################################################### 320 321sub mtr_im_check_mysqlds_alive($) { 322 my $im= shift; 323 324 mtr_debug("Checking for IM-guarded mysqld instances..."); 325 326 my $instances = $im->{'instances'}; 327 328 for ( my $idx= 0; $idx < 2; ++$idx ) 329 { 330 mtr_debug("Checking mysqld[$idx]..."); 331 332 return 1 333 if mtr_im_check_mysqld_alive($instances->[$idx]); 334 } 335} 336 337########################################################################### 338 339sub mtr_im_check_mysqld_alive($) { 340 my $mysqld_instance= shift; 341 342 # Check that the process is dead. 343 344 if ( defined $mysqld_instance->{'pid'} ) 345 { 346 if ( kill (0, $mysqld_instance->{'pid'}) ) 347 { 348 mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive."); 349 return 1; 350 } 351 else 352 { 353 mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead."); 354 } 355 } 356 else 357 { 358 mtr_debug("No PID file for mysqld instance."); 359 } 360 361 # Check that mysqld does not accept client connections. 362 363 if ( mtr_ping_port($mysqld_instance->{'port'}) ) 364 { 365 mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . 366 "is accepting connections."); 367 368 mtr_im_errlog("Mysqld is accepting connections on port " . 369 "$mysqld_instance->{port}, but there is no " . 370 "process information."); 371 return 1; 372 } 373 else 374 { 375 mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . 376 "does not accept connections."); 377 return 0; 378 } 379} 380 381########################################################################### 382 383sub mtr_im_cleanup($) { 384 my $im= shift; 385 386 mtr_im_rm_file($im->{'path_pid'}); 387 mtr_im_rm_file($im->{'path_sock'}); 388 389 mtr_im_rm_file($im->{'path_angel_pid'}); 390 391 for ( my $idx= 0; $idx < 2; ++$idx ) 392 { 393 mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_pid'}); 394 mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_sock'}); 395 } 396} 397 398########################################################################### 399 400sub mtr_im_rm_file($) 401{ 402 my $file_path= shift; 403 404 if ( -f $file_path ) 405 { 406 mtr_debug("Removing '$file_path'..."); 407 408 unless ( unlink($file_path) ) 409 { 410 mtr_warning("Can not remove '$file_path'.") 411 } 412 } 413 else 414 { 415 mtr_debug("File '$file_path' does not exist already."); 416 } 417} 418 419########################################################################### 420 421sub mtr_im_errlog($) { 422 my $msg= shift; 423 424 # Complain in error log so that a warning will be shown. 425 # 426 # TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so 427 # that it can be seen on console and does not produce pushbuild error. 428 429 # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; 430 # 431 # open (ERRLOG, ">>$errlog") || 432 # mtr_error("Can not open error log ($errlog)"); 433 # 434 # my $ts= localtime(); 435 # print ERRLOG 436 # "Warning: [$ts] $msg\n"; 437 # 438 # close ERRLOG; 439 440 my $ts= localtime(); 441 print "Warning: [$ts] $msg\n"; 442} 443 444########################################################################### 445 446sub mtr_im_kill($) { 447 my $im= shift; 448 449 # Re-load PIDs. That can be useful because some processes could have been 450 # restarted. 451 452 mtr_im_load_pids($im); 453 454 # Ignoring SIGCHLD so that all children could rest in peace. 455 456 start_reap_all(); 457 458 # Kill IM-angel first of all. 459 460 if ( defined $im->{'angel_pid'} ) 461 { 462 mtr_debug("Killing IM-angel (PID: $im->{angel_pid})..."); 463 mtr_im_kill_process([ $im->{'angel_pid'} ], 'KILL', 10, 1) 464 } 465 else 466 { 467 mtr_debug("IM-angel is dead."); 468 } 469 470 # Re-load PIDs again. 471 472 mtr_im_load_pids($im); 473 474 # Kill IM-main. 475 476 if ( defined $im->{'pid'} ) 477 { 478 mtr_debug("Killing IM-main (PID: $im->pid})..."); 479 mtr_im_kill_process([ $im->{'pid'} ], 'KILL', 10, 1); 480 } 481 else 482 { 483 mtr_debug("IM-main is dead."); 484 } 485 486 # Re-load PIDs again. 487 488 mtr_im_load_pids($im); 489 490 # Kill guarded mysqld instances. 491 492 my @mysqld_pids; 493 494 mtr_debug("Collecting PIDs of mysqld instances to kill..."); 495 496 for ( my $idx= 0; $idx < 2; ++$idx ) 497 { 498 my $pid= $im->{'instances'}->[$idx]->{'pid'}; 499 500 unless ( defined $pid ) 501 { 502 next; 503 } 504 505 mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid."); 506 507 push (@mysqld_pids, $pid); 508 } 509 510 if ( scalar @mysqld_pids > 0 ) 511 { 512 mtr_debug("Killing IM-guarded mysqld instances..."); 513 mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1); 514 } 515 516 # That's all. 517 518 stop_reap_all(); 519} 520 521############################################################################## 522 523sub mtr_im_wait_for_connection($$$) { 524 my $im= shift; 525 my $total_attempts= shift; 526 my $connect_timeout= shift; 527 528 mtr_debug("Waiting for IM on port $im->{port} " . 529 "to start accepting connections..."); 530 531 for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) 532 { 533 mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)..."); 534 535 if ( mtr_ping_port($im->{'port'}) ) 536 { 537 mtr_debug("IM is accepting connections " . 538 "on port $im->{port}."); 539 return 1; 540 } 541 542 mtr_debug("Sleeping $connect_timeout..."); 543 sleep($connect_timeout); 544 } 545 546 mtr_debug("IM does not accept connections " . 547 "on port $im->{port} after " . 548 ($total_attempts * $connect_timeout) . " seconds."); 549 550 return 0; 551} 552 553############################################################################## 554 555sub mtr_im_wait_for_mysqld($$$) { 556 my $mysqld= shift; 557 my $total_attempts= shift; 558 my $connect_timeout= shift; 559 560 mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " . 561 "to start accepting connections..."); 562 563 for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) 564 { 565 mtr_debug("Trying to connect to mysqld " . 566 "($cur_attempt of $total_attempts)..."); 567 568 if ( mtr_ping_port($mysqld->{'port'}) ) 569 { 570 mtr_debug("Mysqld is accepting connections " . 571 "on port $mysqld->{port}."); 572 return 1; 573 } 574 575 mtr_debug("Sleeping $connect_timeout..."); 576 sleep($connect_timeout); 577 } 578 579 mtr_debug("Mysqld does not accept connections " . 580 "on port $mysqld->{port} after " . 581 ($total_attempts * $connect_timeout) . " seconds."); 582 583 return 0; 584} 585 586############################################################################## 587# 588# Public operations. 589# 590############################################################################## 591 592sub mtr_im_start($$) { 593 my $im = shift; 594 my $opts = shift; 595 596 mtr_debug("Starting Instance Manager..."); 597 598 my $args; 599 mtr_init_args(\$args); 600 mtr_add_arg($args, "--defaults-file=%s", $im->{'defaults_file'}); 601 602 foreach my $opt ( @{$opts} ) 603 { 604 mtr_add_arg($args, $opt); 605 } 606 607 $im->{'spawner_pid'} = 608 mtr_spawn( 609 $::exe_im, # path to the executable 610 $args, # cmd-line args 611 '', # stdin 612 $im->{'path_log'}, # stdout 613 $im->{'path_err'}, # stderr 614 '', # pid file path (not used) 615 { append_log_file => 1 } # append log files 616 ); 617 618 unless ( $im->{'spawner_pid'} ) 619 { 620 mtr_error('Could not start Instance Manager.') 621 } 622 623 # Instance Manager can be run in daemon mode. In this case, it creates 624 # several processes and the parent process, created by mtr_spawn(), exits just 625 # after start. So, we have to obtain Instance Manager PID from the PID file. 626 627 mtr_debug("Waiting for IM to create PID file (" . 628 "path: '$im->{path_pid}'; " . 629 "timeout: $im->{start_timeout})..."); 630 631 unless ( sleep_until_file_created($im->{'path_pid'}, 632 $im->{'start_timeout'}, 633 -1) ) # real PID is still unknown 634 { 635 mtr_debug("IM has not created PID file in $im->{start_timeout} secs."); 636 mtr_debug("Aborting test suite..."); 637 638 mtr_kill_leftovers(); 639 640 mtr_report("IM has not created PID file in $im->{start_timeout} secs."); 641 return 0; 642 } 643 644 $im->{'pid'}= mtr_get_pid_from_file($im->{'path_pid'}); 645 646 mtr_debug("Instance Manager started. PID: $im->{pid}."); 647 648 # Wait until we can connect to IM. 649 650 my $IM_CONNECT_TIMEOUT= 30; 651 652 unless ( mtr_im_wait_for_connection($im, 653 $IM_CONNECT_TIMEOUT, 1) ) 654 { 655 mtr_debug("Can not connect to Instance Manager " . 656 "in $IM_CONNECT_TIMEOUT seconds after start."); 657 mtr_debug("Aborting test suite..."); 658 659 mtr_kill_leftovers(); 660 661 mtr_report("Can not connect to Instance Manager " . 662 "in $IM_CONNECT_TIMEOUT seconds after start."); 663 return 0; 664 } 665 666 # Wait for IM to start guarded instances: 667 # - wait for PID files; 668 669 mtr_debug("Waiting for guarded mysqlds instances to create PID files..."); 670 671 for ( my $idx= 0; $idx < 2; ++$idx ) 672 { 673 my $mysqld= $im->{'instances'}->[$idx]; 674 675 if ( exists $mysqld->{'nonguarded'} ) 676 { 677 next; 678 } 679 680 mtr_debug("Waiting for mysqld[$idx] to create PID file (" . 681 "path: '$mysqld->{path_pid}'; " . 682 "timeout: $mysqld->{start_timeout})..."); 683 684 unless ( sleep_until_file_created($mysqld->{'path_pid'}, 685 $mysqld->{'start_timeout'}, 686 -1) ) # real PID is still unknown 687 { 688 mtr_debug("mysqld[$idx] has not created PID file in " . 689 "$mysqld->{start_timeout} secs."); 690 mtr_debug("Aborting test suite..."); 691 692 mtr_kill_leftovers(); 693 694 mtr_report("mysqld[$idx] has not created PID file in " . 695 "$mysqld->{start_timeout} secs."); 696 return 0; 697 } 698 699 mtr_debug("PID file for mysqld[$idx] ($mysqld->{path_pid} created."); 700 } 701 702 # Wait until we can connect to guarded mysqld-instances 703 # (in other words -- wait for IM to start guarded instances). 704 705 mtr_debug("Waiting for guarded mysqlds to start accepting connections..."); 706 707 for ( my $idx= 0; $idx < 2; ++$idx ) 708 { 709 my $mysqld= $im->{'instances'}->[$idx]; 710 711 if ( exists $mysqld->{'nonguarded'} ) 712 { 713 next; 714 } 715 716 mtr_debug("Waiting for mysqld[$idx] to accept connection..."); 717 718 unless ( mtr_im_wait_for_mysqld($mysqld, 30, 1) ) 719 { 720 mtr_debug("Can not connect to mysqld[$idx] " . 721 "in $IM_CONNECT_TIMEOUT seconds after start."); 722 mtr_debug("Aborting test suite..."); 723 724 mtr_kill_leftovers(); 725 726 mtr_report("Can not connect to mysqld[$idx] " . 727 "in $IM_CONNECT_TIMEOUT seconds after start."); 728 return 0; 729 } 730 731 mtr_debug("mysqld[$idx] started."); 732 } 733 734 mtr_debug("Instance Manager and its components are up and running."); 735 736 return 1; 737} 738 739############################################################################## 740 741sub mtr_im_stop($) { 742 my $im= shift; 743 744 mtr_debug("Stopping Instance Manager..."); 745 746 # Try graceful shutdown. 747 748 mtr_im_terminate($im); 749 750 # Check that all processes died. 751 752 unless ( mtr_im_check_alive($im) ) 753 { 754 mtr_debug("Instance Manager has been stopped successfully."); 755 mtr_im_cleanup($im); 756 return 1; 757 } 758 759 # Instance Manager don't want to die. We should kill it. 760 761 mtr_im_errlog("Instance Manager did not shutdown gracefully."); 762 763 mtr_im_kill($im); 764 765 # Check again that all IM-related processes have been killed. 766 767 my $im_is_alive= mtr_im_check_alive($im); 768 769 mtr_im_cleanup($im); 770 771 if ( $im_is_alive ) 772 { 773 mtr_debug("Can not kill Instance Manager or its children."); 774 return 0; 775 } 776 777 mtr_debug("Instance Manager has been killed successfully."); 778 return 1; 779} 780 781########################################################################### 782 7831; 784