~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
# -*- cperl -*-
2
# Copyright (C) 2004-2006 MySQL AB
3
# 
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; version 2 of the License.
7
# 
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
# 
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16
17
# This is a library file used by the Perl version of mysql-test-run,
18
# and is part of the translation of the Bourne shell script with the
19
# same name.
20
21
use Socket;
22
use Errno;
23
use strict;
24
25
use POSIX qw(WNOHANG SIGHUP);
26
27
sub mtr_run ($$$$$$;$);
28
sub mtr_spawn ($$$$$$;$);
29
sub mtr_check_stop_servers ($);
30
sub mtr_kill_leftovers ();
31
sub mtr_wait_blocking ($);
32
sub mtr_record_dead_children ();
33
sub mtr_ndbmgm_start($$);
34
sub mtr_mysqladmin_start($$$);
35
sub mtr_exit ($);
36
sub sleep_until_file_created ($$$);
37
sub mtr_kill_processes ($);
38
sub mtr_ping_with_timeout($);
39
sub mtr_ping_port ($);
40
41
# Local function
42
sub spawn_impl ($$$$$$$);
43
44
##############################################################################
45
#
46
#  Execute an external command
47
#
48
##############################################################################
49
50
sub mtr_run ($$$$$$;$) {
51
  my $path=       shift;
52
  my $arg_list_t= shift;
53
  my $input=      shift;
54
  my $output=     shift;
55
  my $error=      shift;
56
  my $pid_file=   shift; # Not used
57
  my $spawn_opts= shift;
58
59
  return spawn_impl($path,$arg_list_t,'run',$input,$output,$error,
60
    $spawn_opts);
61
}
62
63
sub mtr_run_test ($$$$$$;$) {
64
  my $path=       shift;
65
  my $arg_list_t= shift;
66
  my $input=      shift;
67
  my $output=     shift;
68
  my $error=      shift;
69
  my $pid_file=   shift; # Not used
70
  my $spawn_opts= shift;
71
72
  return spawn_impl($path,$arg_list_t,'test',$input,$output,$error,
73
    $spawn_opts);
74
}
75
76
sub mtr_spawn ($$$$$$;$) {
77
  my $path=       shift;
78
  my $arg_list_t= shift;
79
  my $input=      shift;
80
  my $output=     shift;
81
  my $error=      shift;
82
  my $pid_file=   shift; # Not used
83
  my $spawn_opts= shift;
84
85
  return spawn_impl($path,$arg_list_t,'spawn',$input,$output,$error,
86
    $spawn_opts);
87
}
88
89
90
91
sub spawn_impl ($$$$$$$) {
92
  my $path=       shift;
93
  my $arg_list_t= shift;
94
  my $mode=       shift;
95
  my $input=      shift;
96
  my $output=     shift;
97
  my $error=      shift;
98
  my $spawn_opts= shift;
99
100
  if ( $::opt_script_debug )
101
  {
102
    mtr_report("");
103
    mtr_debug("-" x 73);
104
    mtr_debug("STDIN  $input") if $input;
105
    mtr_debug("STDOUT $output") if $output;
106
    mtr_debug("STDERR $error") if $error;
107
    mtr_debug("$mode: $path ", join(" ",@$arg_list_t));
108
    mtr_debug("spawn options:");
109
    if ($spawn_opts)
110
    {
111
      foreach my $key (sort keys %{$spawn_opts})
112
      {
113
        mtr_debug("  - $key: $spawn_opts->{$key}");
114
      }
115
    }
116
    else
117
    {
118
      mtr_debug("  none");
119
    }
120
    mtr_debug("-" x 73);
121
    mtr_report("");
122
  }
123
124
  mtr_error("Can't spawn with empty \"path\"") unless defined $path;
125
126
127
 FORK:
128
  {
129
    my $pid= fork();
130
131
    if ( ! defined $pid )
132
    {
133
      if ( $! == $!{EAGAIN} )           # See "perldoc Errno"
134
      {
135
        mtr_warning("Got EAGAIN from fork(), sleep 1 second and redo");
136
        sleep(1);
137
        redo FORK;
138
      }
139
140
      mtr_error("$path ($pid) can't be forked, error: $!");
141
142
    }
143
144
    if ( $pid )
145
    {
146
      select(STDOUT) if $::glob_win32_perl;
147
      return spawn_parent_impl($pid,$mode,$path);
148
    }
149
    else
150
    {
151
      # Child, redirect output and exec
152
153
      $SIG{INT}= 'DEFAULT';         # Parent do some stuff, we don't
154
155
      my $log_file_open_mode = '>';
156
157
      if ($spawn_opts and $spawn_opts->{'append_log_file'})
158
      {
159
        $log_file_open_mode = '>>';
160
      }
161
162
      if ( $output )
163
      {
164
	if ( $::glob_win32_perl )
165
	{
166
	  # Don't redirect stdout on ActiveState perl since this is
167
          # just another thread in the same process.
168
	}
169
        elsif ( ! open(STDOUT,$log_file_open_mode,$output) )
170
        {
171
          mtr_child_error("can't redirect STDOUT to \"$output\": $!");
172
        }
173
      }
174
175
      if ( $error )
176
      {
177
        if ( !$::glob_win32_perl and $output eq $error )
178
        {
179
          if ( ! open(STDERR,">&STDOUT") )
180
          {
181
            mtr_child_error("can't dup STDOUT: $!");
182
          }
183
        }
184
        else
185
        {
186
          if ( ! open(STDERR,$log_file_open_mode,$error) )
187
          {
188
            mtr_child_error("can't redirect STDERR to \"$error\": $!");
189
          }
190
        }
191
      }
192
193
      if ( $input )
194
      {
195
        if ( ! open(STDIN,"<",$input) )
196
        {
197
          mtr_child_error("can't redirect STDIN to \"$input\": $!");
198
        }
199
      }
200
201
      if ( ! exec($path,@$arg_list_t) )
202
      {
203
        mtr_child_error("failed to execute \"$path\": $!");
204
      }
205
      mtr_error("Should never come here 1!");
206
    }
207
    mtr_error("Should never come here 2!");
208
  }
209
  mtr_error("Should never come here 3!");
210
}
211
212
213
sub spawn_parent_impl {
214
  my $pid=  shift;
215
  my $mode= shift;
216
  my $path= shift;
217
218
  if ( $mode eq 'run' or $mode eq 'test' )
219
  {
220
    if ( $mode eq 'run' )
221
    {
222
      # Simple run of command, wait blocking for it to return
223
      my $ret_pid= waitpid($pid,0);
224
      if ( $ret_pid != $pid )
225
      {
226
	# The "simple" waitpid has failed, print debug info
227
	# and try to handle the error
228
        mtr_warning("waitpid($pid, 0) returned $ret_pid " .
229
		    "when waiting for '$path', error: '$!'");
230
	if ( $ret_pid == -1 )
231
	{
232
	  # waitpid returned -1, that would indicate the process
233
	  # no longer exist and waitpid couldn't wait for it.
234
	  return 1;
235
	}
236
	mtr_error("Error handling failed");
237
      }
238
239
      return mtr_process_exit_status($?);
240
    }
241
    else
242
    {
243
      # We run mysqltest and wait for it to return. But we try to
244
      # catch dying mysqld processes as well.
245
      #
246
      # We do blocking waitpid() until we get the return from the
247
      # "mysqltest" call. But if a mysqld process dies that we
248
      # started, we take this as an error, and kill mysqltest.
249
250
251
      my $exit_value= -1;
252
      my $saved_exit_value;
253
      my $ret_pid;                      # What waitpid() returns
254
255
      while ( ($ret_pid= waitpid(-1,0)) != -1 )
256
      {
257
        # Someone terminated, don't know who. Collect
258
        # status info first before $? is lost,
259
        # but not $exit_value, this is flagged from
260
261
        my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid);
262
        if ( $timer_name )
263
        {
264
          if ( $timer_name eq "suite" )
265
          {
266
            # We give up here
267
            # FIXME we should only give up the suite, not all of the run?
268
            print STDERR "\n";
269
            mtr_error("Test suite timeout");
270
          }
271
          elsif ( $timer_name eq "testcase" )
272
          {
273
            $saved_exit_value=  63;       # Mark as timeout
274
            kill(9, $pid);                # Kill mysqltest
275
            next;                         # Go on and catch the termination
276
          }
277
        }
278
279
        if ( $ret_pid == $pid )
280
        {
281
          # We got termination of mysqltest, we are done
282
          $exit_value= mtr_process_exit_status($?);
283
          last;
284
        }
285
286
        # One of the child processes died, unless this was expected
287
	# mysqltest should be killed and test aborted
288
289
	check_expected_crash_and_restart($ret_pid);
290
      }
291
292
      if ( $ret_pid != $pid )
293
      {
294
        # We terminated the waiting because a "mysqld" process died.
295
        # Kill the mysqltest process.
296
	mtr_verbose("Kill mysqltest because another process died");
297
        kill(9,$pid);
298
299
        $ret_pid= waitpid($pid,0);
300
301
        if ( $ret_pid != $pid )
302
        {
303
          mtr_error("$path ($pid) got lost somehow");
304
        }
305
      }
306
307
      return $saved_exit_value || $exit_value;
308
    }
309
  }
310
  else
311
  {
312
    # We spawned a process we don't wait for
313
    return $pid;
314
  }
315
}
316
317
318
# ----------------------------------------------------------------------
319
# We try to emulate how an Unix shell calculates the exit code
320
# ----------------------------------------------------------------------
321
322
sub mtr_process_exit_status {
323
  my $raw_status= shift;
324
325
  if ( $raw_status & 127 )
326
  {
327
    return ($raw_status & 127) + 128;  # Signal num + 128
328
  }
329
  else
330
  {
331
    return $raw_status >> 8;           # Exit code
332
  }
333
}
334
335
336
##############################################################################
337
#
338
#  Kill processes left from previous runs
339
#
340
##############################################################################
341
342
343
# Kill all processes(mysqld, ndbd, ndb_mgmd and im) that would conflict with
344
# this run
345
# Make sure to remove the PID file, if any.
346
# kill IM manager first, else it will restart the servers
347
sub mtr_kill_leftovers () {
348
349
  mtr_report("Killing Possible Leftover Processes");
350
  mtr_debug("mtr_kill_leftovers(): started.");
351
352
  my @kill_pids;
353
  my %admin_pids;
354
355
  foreach my $srv (@{$::master}, @{$::slave})
356
  {
357
    mtr_debug("  - mysqld " .
358
              "(pid: $srv->{pid}; " .
359
              "pid file: '$srv->{path_pid}'; " .
360
              "socket: '$srv->{path_sock}'; ".
361
              "port: $srv->{port})");
362
363
    my $pid= mtr_mysqladmin_start($srv, "shutdown", 20);
364
365
    # Save the pid of the mysqladmin process
366
    $admin_pids{$pid}= 1;
367
368
    push(@kill_pids,{
369
		     pid      => $srv->{'pid'},
370
		     pidfile  => $srv->{'path_pid'},
371
		     sockfile => $srv->{'path_sock'},
372
		     port     => $srv->{'port'},
373
		    });
374
    $srv->{'pid'}= 0; # Assume we are done with it
375
  }
376
377
  # Wait for all the admin processes to complete
378
  mtr_wait_blocking(\%admin_pids);
379
380
  # If we trusted "mysqladmin --shutdown_timeout= ..." we could just
381
  # terminate now, but we don't (FIXME should be debugged).
382
  # So we try again to ping and at least wait the same amount of time
383
  # mysqladmin would for all to die.
384
385
  mtr_ping_with_timeout(\@kill_pids);
386
387
  # We now have tried to terminate nice. We have waited for the listen
388
  # port to be free, but can't really tell if the mysqld process died
389
  # or not. We now try to find the process PID from the PID file, and
390
  # send a kill to that process. Note that Perl let kill(0,@pids) be
391
  # a way to just return the numer of processes the kernel can send
392
  # signals to. So this can be used (except on Cygwin) to determine
393
  # if there are processes left running that we cound out might exists.
394
  #
395
  # But still after all this work, all we know is that we have
396
  # the ports free.
397
398
  # We scan the "var/run/" directory for other process id's to kill
399
400
  my $rundir= "$::opt_vardir/run";
401
402
  mtr_debug("Processing PID files in directory '$rundir'...");
403
404
  if ( -d $rundir )
405
  {
406
    opendir(RUNDIR, $rundir)
407
      or mtr_error("can't open directory \"$rundir\": $!");
408
409
    my @pids;
410
411
    while ( my $elem= readdir(RUNDIR) )
412
    {
413
      # Only read pid from files that end with .pid
414
      if ( $elem =~ /.*[.]pid$/)
415
      {
416
	my $pidfile= "$rundir/$elem";
417
418
	if ( -f $pidfile )
419
	{
420
	  mtr_debug("Processing PID file: '$pidfile'...");
421
422
	  my $pid= mtr_get_pid_from_file($pidfile);
423
424
	  mtr_debug("Got pid: $pid from file '$pidfile'");
425
426
	  if ( $::glob_cygwin_perl or kill(0, $pid) )
427
	  {
428
	    mtr_debug("There is process with pid $pid -- scheduling for kill.");
429
	    push(@pids, $pid);            # We know (cygwin guess) it exists
430
	  }
431
	  else
432
	  {
433
	    mtr_debug("There is no process with pid $pid -- skipping.");
434
	  }
435
	}
436
      }
437
      else
438
      {
439
	mtr_warning("Found non pid file $elem in $rundir")
440
	  if -f "$rundir/$elem";
441
	next;
442
      }
443
    }
444
    closedir(RUNDIR);
445
446
    if ( @pids )
447
    {
448
      mtr_debug("Killing the following processes with PID files: " .
449
                join(' ', @pids) . "...");
450
451
      start_reap_all();
452
453
      if ( $::glob_cygwin_perl )
454
      {
455
        # We have no (easy) way of knowing the Cygwin controlling
456
        # process, in the PID file we only have the Windows process id.
457
        system("kill -f " . join(" ",@pids)); # Hope for the best....
458
        mtr_debug("Sleep 5 seconds waiting for processes to die");
459
        sleep(5);
460
      }
461
      else
462
      {
463
        my $retries= 10;                    # 10 seconds
464
        do
465
        {
466
          mtr_debug("Sending SIGKILL to pids: " . join(' ', @pids));
467
          kill(9, @pids);
468
          mtr_report("Sleep 1 second waiting for processes to die");
469
          sleep(1)                      # Wait one second
470
        } while ( $retries-- and  kill(0, @pids) );
471
472
        if ( kill(0, @pids) )           # Check if some left
473
        {
474
          mtr_warning("can't kill process(es) " . join(" ", @pids));
475
        }
476
      }
477
478
      stop_reap_all();
479
    }
480
  }
481
  else
482
  {
483
    mtr_debug("Directory for PID files ($rundir) does not exist.");
484
  }
485
486
  # We may have failed everything, but we now check again if we have
487
  # the listen ports free to use, and if they are free, just go for it.
488
489
  mtr_debug("Checking known mysqld servers...");
490
491
  foreach my $srv ( @kill_pids )
492
  {
493
    if ( defined $srv->{'port'} and mtr_ping_port($srv->{'port'}) )
494
    {
495
      mtr_warning("can't kill old process holding port $srv->{'port'}");
496
    }
497
  }
498
499
  mtr_debug("mtr_kill_leftovers(): finished.");
500
}
501
502
503
#
504
# Check that all processes in "spec" are shutdown gracefully
505
# else kill them off hard
506
#
507
sub mtr_check_stop_servers ($) {
508
  my $spec=  shift;
509
510
  # Return if no processes are defined
511
  return if ! @$spec;
512
513
  mtr_verbose("mtr_check_stop_servers");
514
515
  # ----------------------------------------------------------------------
516
  # Wait until servers in "spec" has stopped listening
517
  # to their ports or timeout occurs
518
  # ----------------------------------------------------------------------
519
  mtr_ping_with_timeout(\@$spec);
520
521
  # ----------------------------------------------------------------------
522
  # Use waitpid() nonblocking for a little while, to see how
523
  # many process's will exit sucessfully.
524
  # This is the normal case.
525
  # ----------------------------------------------------------------------
779.3.36 by Monty Taylor
Fixed timeout problem. Should probably not hardcode this, but screw it.
526
  my $wait_counter= 100; # Max number of times to redo the loop
1 by brian
clean slate
527
  foreach my $srv ( @$spec )
528
  {
529
    my $pid= $srv->{'pid'};
530
    my $ret_pid;
531
    if ( $pid )
532
    {
533
      $ret_pid= waitpid($pid,&WNOHANG);
534
      if ($ret_pid == $pid)
535
      {
536
	mtr_verbose("Caught exit of process $ret_pid");
537
	$srv->{'pid'}= 0;
538
      }
539
      elsif ($ret_pid == 0)
540
      {
541
	mtr_verbose("Process $pid is still alive");
542
	if ($wait_counter-- > 0)
543
	{
544
	  # Give the processes more time to exit
545
	  select(undef, undef, undef, (0.1));
546
	  redo;
547
	}
548
      }
549
      else
550
      {
551
	mtr_warning("caught exit of unknown child $ret_pid");
552
      }
553
    }
554
  }
555
556
  # ----------------------------------------------------------------------
557
  # The processes that haven't yet exited need to
558
  # be killed hard, put them in "kill_pids" hash
559
  # ----------------------------------------------------------------------
560
  my %kill_pids;
561
  foreach my $srv ( @$spec )
562
  {
563
    my $pid= $srv->{'pid'};
564
    if ( $pid )
565
    {
566
      # Server is still alive, put it in list to be hard killed
567
      if ($::glob_win32_perl)
568
      {
569
	# Kill the real process if it's known
570
	$pid= $srv->{'real_pid'} if ($srv->{'real_pid'});
571
      }
572
      $kill_pids{$pid}= 1;
573
574
      # Write a message to the process's error log (if it has one)
575
      # that it's being killed hard.
576
      if ( defined $srv->{'errfile'} )
577
      {
578
	mtr_tofile($srv->{'errfile'}, "Note: Forcing kill of process $pid\n");
579
      }
580
      mtr_warning("Forcing kill of process $pid");
581
582
    }
583
    else
584
    {
585
      # Server is dead, remove the pidfile if it exists
586
      #
587
      # Race, could have been removed between test with -f
588
      # and the unlink() below, so better check again with -f
589
      if ( -f $srv->{'pidfile'} and ! unlink($srv->{'pidfile'}) and
590
           -f $srv->{'pidfile'} )
591
      {
592
        mtr_error("can't remove $srv->{'pidfile'}");
593
      }
594
    }
595
  }
596
597
  if ( ! keys %kill_pids )
598
  {
599
    # All processes has exited gracefully
600
    return;
601
  }
602
603
  mtr_kill_processes(\%kill_pids);
604
605
  # ----------------------------------------------------------------------
606
  # All processes are killed, cleanup leftover files
607
  # ----------------------------------------------------------------------
608
  {
609
    my $errors= 0;
610
    foreach my $srv ( @$spec )
611
    {
612
      if ( $srv->{'pid'} )
613
      {
614
	# Server has been hard killed, clean it's resources
615
	foreach my $file ($srv->{'pidfile'}, $srv->{'sockfile'})
616
        {
617
	  # Know it is dead so should be no race, careful anyway
618
	  if ( defined $file and -f $file and ! unlink($file) and -f $file )
619
          {
620
	    $errors++;
621
	    mtr_warning("couldn't delete $file");
622
	  }
623
	}
624
625
	if ($::glob_win32_perl and $srv->{'real_pid'})
626
	{
627
	  # Wait for the pseudo pid - if the real_pid was known
628
	  # the pseudo pid has not been waited for yet, wai blocking
629
	  # since it's "such a simple program"
630
	  mtr_verbose("Wait for pseudo process $srv->{'pid'}");
631
	  my $ret_pid= waitpid($srv->{'pid'}, 0);
632
	  mtr_verbose("Pseudo process $ret_pid died");
633
	}
634
635
	$srv->{'pid'}= 0;
636
      }
637
    }
638
    if ( $errors )
639
    {
640
      # There where errors killing processes
641
      # do one last attempt to ping the servers
642
      # and if they can't be pinged, assume they are dead
643
      if ( ! mtr_ping_with_timeout( \@$spec ) )
644
      {
645
	mtr_error("we could not kill or clean up all processes");
646
      }
647
      else
648
      {
649
	mtr_verbose("All ports were free, continuing");
650
      }
651
    }
652
  }
653
}
654
655
656
# Wait for all the process in the list to terminate
657
sub mtr_wait_blocking($) {
658
  my $admin_pids= shift;
659
660
661
  # Return if no processes defined
662
  return if ! %$admin_pids;
663
664
  mtr_verbose("mtr_wait_blocking");
665
666
  # Wait for all the started processes to exit
667
  # As mysqladmin is such a simple program, we trust it to terminate itself.
668
  # I.e. we wait blocking, and wait for them all before we go on.
669
  foreach my $pid (keys %{$admin_pids})
670
  {
671
    my $ret_pid= waitpid($pid,0);
672
673
  }
674
}
675
676
# Start "mysqladmin <command>" for a specific mysqld
677
sub mtr_mysqladmin_start($$$) {
678
  my $srv= shift;
679
  my $command= shift;
680
  my $adm_shutdown_tmo= shift;
681
682
  my $args;
683
  mtr_init_args(\$args);
684
685
  mtr_add_arg($args, "--no-defaults");
686
  mtr_add_arg($args, "--user=%s", $::opt_user);
687
  mtr_add_arg($args, "--password=");
688
  mtr_add_arg($args, "--silent");
689
  if ( -e $srv->{'path_sock'} )
690
  {
691
    mtr_add_arg($args, "--socket=%s", $srv->{'path_sock'});
692
  }
693
  if ( $srv->{'port'} )
694
  {
695
    mtr_add_arg($args, "--port=%s", $srv->{'port'});
696
  }
697
  mtr_add_arg($args, "--connect_timeout=5");
698
699
  # Shutdown time must be high as slave may be in reconnect
700
  mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo");
701
  mtr_add_arg($args, "$command");
77.3.9 by Monty Taylor
Renamed client programs to drizzle.
702
  my $pid= mtr_spawn($::exe_drizzleadmin, $args,
1 by brian
clean slate
703
		     "", "", "", "",
704
		     { append_log_file => 1 });
705
  mtr_verbose("mtr_mysqladmin_start, pid: $pid");
706
  return $pid;
707
708
}
709
710
# Start "ndb_mgm shutdown" for a specific cluster, it will
711
# shutdown all data nodes and leave the ndb_mgmd running
712
sub mtr_ndbmgm_start($$) {
713
  my $cluster= shift;
714
  my $command= shift;
715
716
  my $args;
717
718
  mtr_init_args(\$args);
719
720
  mtr_add_arg($args, "--no-defaults");
721
  mtr_add_arg($args, "--core");
722
  mtr_add_arg($args, "--try-reconnect=1");
723
  mtr_add_arg($args, "--ndb_connectstring=%s", $cluster->{'connect_string'});
724
  mtr_add_arg($args, "-e");
725
  mtr_add_arg($args, "$command");
726
727
  my $pid= mtr_spawn($::exe_ndb_mgm, $args,
728
		     "", "/dev/null", "/dev/null", "",
729
		     {});
730
  mtr_verbose("mtr_ndbmgm_start, pid: $pid");
731
  return $pid;
732
733
}
734
735
736
# Ping all servers in list, exit when none of them answers
737
# or when timeout has passed
738
sub mtr_ping_with_timeout($) {
739
  my $spec= shift;
740
  my $timeout= 200;                     # 20 seconds max
741
  my $res= 1;                           # If we just fall through, we are done
742
                                        # in the sense that the servers don't
743
                                        # listen to their ports any longer
744
745
  mtr_debug("Waiting for mysqld servers to stop...");
746
747
 TIME:
748
  while ( $timeout-- )
749
  {
750
    foreach my $srv ( @$spec )
751
    {
752
      $res= 1;                          # We are optimistic
753
      if ( $srv->{'pid'} and defined $srv->{'port'} )
754
      {
755
	if ( mtr_ping_port($srv->{'port'}) )
756
	{
757
	  mtr_verbose("waiting for process $srv->{'pid'} to stop ".
758
		      "using port $srv->{'port'}");
759
760
	  # Millisceond sleep emulated with select
761
	  select(undef, undef, undef, (0.1));
762
	  $res= 0;
763
	  next TIME;
764
	}
765
	else
766
	{
767
	  # Process was not using port
768
	}
769
      }
770
    }
771
    last;                               # If we got here, we are done
772
  }
773
774
  if ($res)
775
  {
776
    mtr_debug("mtr_ping_with_timeout(): All mysqld instances are down.");
777
  }
778
  else
779
  {
780
    mtr_report("mtr_ping_with_timeout(): At least one server is alive.");
781
  }
782
783
  return $res;
784
}
785
786
787
#
788
# Loop through our list of processes and look for and entry
789
# with the provided pid
790
# Set the pid of that process to 0 if found
791
#
792
sub mark_process_dead($)
793
{
794
  my $ret_pid= shift;
795
796
  foreach my $mysqld (@{$::master}, @{$::slave})
797
  {
798
    if ( $mysqld->{'pid'} eq $ret_pid )
799
    {
800
      mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid");
801
      $mysqld->{'pid'}= 0;
802
      return;
803
    }
804
  }
805
806
  foreach my $cluster (@{$::clusters})
807
  {
808
    if ( $cluster->{'pid'} eq $ret_pid )
809
    {
810
      mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid");
811
      $cluster->{'pid'}= 0;
812
      return;
813
    }
814
815
    foreach my $ndbd (@{$cluster->{'ndbds'}})
816
    {
817
      if ( $ndbd->{'pid'} eq $ret_pid )
818
      {
819
	mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid");
820
	$ndbd->{'pid'}= 0;
821
	return;
822
      }
823
    }
824
  }
825
  mtr_warning("mark_process_dead couldn't find an entry for pid: $ret_pid");
826
827
}
828
829
#
830
# Loop through our list of processes and look for and entry
831
# with the provided pid, if found check for the file indicating
832
# expected crash and restart it.
833
#
834
sub check_expected_crash_and_restart($)
835
{
836
  my $ret_pid= shift;
837
838
  foreach my $mysqld (@{$::master}, @{$::slave})
839
  {
840
    if ( $mysqld->{'pid'} eq $ret_pid )
841
    {
842
      mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid");
843
      $mysqld->{'pid'}= 0;
844
845
      # Check if crash expected and restart if it was
846
      my $expect_file= "$::opt_vardir/tmp/" . "$mysqld->{'type'}" .
847
	"$mysqld->{'idx'}" . ".expect";
848
      if ( -f $expect_file )
849
      {
850
	mtr_verbose("Crash was expected, file $expect_file exists");
851
	mysqld_start($mysqld, $mysqld->{'start_opts'},
852
		     $mysqld->{'start_slave_master_info'});
853
	unlink($expect_file);
854
      }
855
856
      return;
857
    }
858
  }
859
860
  foreach my $cluster (@{$::clusters})
861
  {
862
    if ( $cluster->{'pid'} eq $ret_pid )
863
    {
864
      mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid");
865
      $cluster->{'pid'}= 0;
866
867
      # Check if crash expected and restart if it was
868
      my $expect_file= "$::opt_vardir/tmp/ndb_mgmd_" . "$cluster->{'type'}" .
869
	".expect";
870
      if ( -f $expect_file )
871
      {
872
	mtr_verbose("Crash was expected, file $expect_file exists");
873
	ndbmgmd_start($cluster);
874
	unlink($expect_file);
875
      }
876
      return;
877
    }
878
879
    foreach my $ndbd (@{$cluster->{'ndbds'}})
880
    {
881
      if ( $ndbd->{'pid'} eq $ret_pid )
882
      {
883
	mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid");
884
	$ndbd->{'pid'}= 0;
885
886
	# Check if crash expected and restart if it was
887
	my $expect_file= "$::opt_vardir/tmp/ndbd_" . "$cluster->{'type'}" .
888
	  "$ndbd->{'idx'}" . ".expect";
889
	if ( -f $expect_file )
890
	{
891
	  mtr_verbose("Crash was expected, file $expect_file exists");
892
	  ndbd_start($cluster, $ndbd->{'idx'},
893
		     $ndbd->{'start_extra_args'});
894
	  unlink($expect_file);
895
	}
896
	return;
897
      }
898
    }
899
  }
900
901
  if ($::instance_manager->{'spawner_pid'} eq $ret_pid)
902
  {
903
    return;
904
  }
905
906
  mtr_warning("check_expected_crash_and_restart couldn't find an entry for pid: $ret_pid");
907
908
}
909
910
##############################################################################
911
#
912
#  The operating system will keep information about dead children, 
913
#  we read this information here, and if we have records the process
914
#  is alive, we mark it as dead.
915
#
916
##############################################################################
917
918
sub mtr_record_dead_children () {
919
920
  my $process_died= 0;
921
  my $ret_pid;
922
923
  # Wait without blockinng to see if any processes had died
924
  # -1 or 0 means there are no more procesess to wait for
925
  while ( ($ret_pid= waitpid(-1,&WNOHANG)) != 0 and $ret_pid != -1)
926
  {
927
    mtr_warning("mtr_record_dead_children: $ret_pid");
928
    mark_process_dead($ret_pid);
929
    $process_died= 1;
930
  }
931
  return $process_died;
932
}
933
934
sub start_reap_all {
935
  # This causes terminating processes to not become zombies, avoiding
936
  # the need for (or possibility of) explicit waitpid().
937
  $SIG{CHLD}= 'IGNORE';
938
939
  # On some platforms (Linux, QNX, OSX, ...) there is potential race
940
  # here. If a process terminated before setting $SIG{CHLD} (but after
941
  # any attempt to waitpid() it), it will still be a zombie. So we
942
  # have to handle any such process here.
943
  my $pid;
944
  while(($pid= waitpid(-1, &WNOHANG)) != 0 and $pid != -1)
945
  {
946
    mtr_warning("start_reap_all pid: $pid");
947
    mark_process_dead($pid);
948
  };
949
}
950
951
sub stop_reap_all {
952
  $SIG{CHLD}= 'DEFAULT';
953
}
954
955
956
sub mtr_ping_port ($) {
957
  my $port= shift;
958
959
  mtr_verbose("mtr_ping_port: $port");
960
961
  my $remote= "localhost";
962
  my $iaddr=  inet_aton($remote);
963
  if ( ! $iaddr )
964
  {
965
    mtr_error("can't find IP number for $remote");
966
  }
967
  my $paddr=  sockaddr_in($port, $iaddr);
968
  my $proto=  getprotobyname('tcp');
969
  if ( ! socket(SOCK, PF_INET, SOCK_STREAM, $proto) )
970
  {
971
    mtr_error("can't create socket: $!");
972
  }
973
974
  mtr_debug("Pinging server (port: $port)...");
975
976
  if ( connect(SOCK, $paddr) )
977
  {
978
    close(SOCK);                        # FIXME check error?
979
    mtr_verbose("USED");
980
    return 1;
981
  }
982
  else
983
  {
984
    mtr_verbose("FREE");
985
    return 0;
986
  }
987
}
988
989
##############################################################################
990
#
991
#  Wait for a file to be created
992
#
993
##############################################################################
994
995
# FIXME check that the pidfile contains the expected pid!
996
997
sub sleep_until_file_created ($$$) {
998
  my $pidfile= shift;
999
  my $timeout= shift;
1000
  my $pid=     shift;
1001
  my $sleeptime= 100; # Milliseconds
1002
  my $loops= ($timeout * 1000) / $sleeptime;
1003
1004
  for ( my $loop= 1; $loop <= $loops; $loop++ )
1005
  {
1006
    if ( -r $pidfile )
1007
    {
1008
      return 1;
1009
    }
1010
1011
    # Check if it died after the fork() was successful
1012
    if ( $pid != 0 && waitpid($pid,&WNOHANG) == $pid )
1013
    {
1014
      mtr_warning("Process $pid died");
1015
      return 0;
1016
    }
1017
1018
    mtr_debug("Sleep $sleeptime milliseconds waiting for $pidfile");
1019
1020
    # Print extra message every 60 seconds
1021
    my $seconds= ($loop * $sleeptime) / 1000;
1022
    if ( $seconds > 1 and int($seconds * 10) % 600 == 0 )
1023
    {
1024
      my $left= $timeout - $seconds;
1025
      mtr_warning("Waited $seconds seconds for $pidfile to be created, " .
1026
                  "still waiting for $left seconds...");
1027
    }
1028
1029
    # Millisceond sleep emulated with select
1030
    select(undef, undef, undef, ($sleeptime/1000));
1031
  }
1032
1033
  return 0;
1034
}
1035
1036
1037
sub mtr_kill_processes ($) {
1038
  my $pids = shift;
1039
1040
  mtr_verbose("mtr_kill_processes (" . join(" ", keys %{$pids}) . ")");
1041
1042
  foreach my $pid (keys %{$pids})
1043
  {
1044
1045
    if ($pid <= 0)
1046
    {
1047
      mtr_warning("Trying to kill illegal pid: $pid");
1048
      next;
1049
    }
1050
1051
    my $signaled_procs= kill(9, $pid);
1052
    if ($signaled_procs == 0)
1053
    {
1054
      # No such process existed, assume it's killed
1055
      mtr_verbose("killed $pid(no such process)");
1056
    }
1057
    else
1058
    {
1059
      my $ret_pid= waitpid($pid,0);
1060
      if ($ret_pid == $pid)
1061
      {
1062
	mtr_verbose("killed $pid(got the pid)");
1063
      }
1064
      elsif ($ret_pid == -1)
1065
      {
1066
	mtr_verbose("killed $pid(got -1)");
1067
      }
1068
    }
1069
  }
1070
  mtr_verbose("done killing processes");
1071
}
1072
1073
1074
##############################################################################
1075
#
1076
#  When we exit, we kill off all children
1077
#
1078
##############################################################################
1079
1080
sub mtr_exit ($) {
1081
  my $code= shift;
1082
  mtr_timer_stop_all($::glob_timers);
1083
  local $SIG{HUP} = 'IGNORE';
1084
  # ToDo: Signalling -$$ will only work if we are the process group
1085
  # leader (in fact on QNX it will signal our session group leader,
1086
  # which might be Do-compile or Pushbuild, causing tests to be
1087
  # aborted). So we only do it if we are the group leader. We might
1088
  # set ourselves as the group leader at startup (with
1089
  # POSIX::setpgrp(0,0)), but then care must be needed to always do
1090
  # proper child process cleanup.
1091
  POSIX::kill(SIGHUP, -$$) if !$::glob_win32_perl and $$ == getpgrp();
1092
1093
  exit($code);
1094
}
1095
1096
###########################################################################
1097
1098
1;