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# 26# This file is used from mysql-test-run.pl when choosing 27# port numbers and directories to use for running mysqld. 28# 29 30use strict; 31use Fcntl ':flock'; 32 33# 34# Requested IDs are stored in a hash and released upon END. 35# 36my %mtr_unique_assigned_ids = (); 37my $mtr_unique_pid; 38BEGIN { 39 $mtr_unique_pid = $$ unless defined $mtr_unique_pid; 40} 41END { 42 if($mtr_unique_pid == $$) { 43 while(my ($id,$file) = each(%mtr_unique_assigned_ids)) { 44 print "Autoreleasing $file:$id\n"; 45 mtr_release_unique_id($file, $id); 46 } 47 } 48} 49 50# 51# Require a unique, numerical ID, given a file name (where all 52# requested IDs are stored), a minimum and a maximum value. 53# 54# We use flock to implement locking for the ID file and ignore 55# possible problems arising from lack of support for it on 56# some platforms (it should work on most, and the possible 57# race condition would occur rarely). The proper solution for 58# this is a daemon that manages IDs, of course. 59# 60# If no unique ID within the specified parameters can be 61# obtained, return undef. 62# 63sub mtr_require_unique_id($$$) { 64 my $file = shift; 65 my $min = shift; 66 my $max = shift; 67 my $ret = undef; 68 my $changed = 0; 69 70 my $can_use_ps = `ps -e | grep '^[ ]*$$ '`; 71 72 if(eval("readlink '$file'") || eval("readlink '$file.sem'")) { 73 die 'lock file is a symbolic link'; 74 } 75 76 chmod 0777, "$file.sem"; 77 open SEM, ">", "$file.sem" or die "can't write to $file.sem"; 78 flock SEM, LOCK_EX or die "can't lock $file.sem"; 79 if(! -e $file) { 80 open FILE, ">", $file or die "can't create $file"; 81 close FILE; 82 } 83 84 if(eval("readlink '$file'") || eval("readlink '$file.sem'")) { 85 die 'lock file is a symbolic link'; 86 } 87 88 chmod 0777, $file; 89 open FILE, "+<", $file or die "can't open $file"; 90 select undef,undef,undef,0.2; 91 seek FILE, 0, 0; 92 my %taken = (); 93 while(<FILE>) { 94 chomp; 95 my ($id, $pid) = split / /; 96 $taken{$id} = $pid; 97 if($can_use_ps) { 98 my $res = `ps -e | grep '^[ ]*$pid '`; 99 if(!$res) { 100 print "Ignoring slot $id used by missing process $pid.\n"; 101 delete $taken{$id}; 102 ++$changed; 103 } 104 } 105 } 106 for(my $i=$min; $i<=$max; ++$i) { 107 if(! exists $taken{$i}) { 108 $ret = $i; 109 $taken{$i} = $$; 110 ++$changed; 111 last; 112 } 113 } 114 if($changed) { 115 seek FILE, 0, 0; 116 truncate FILE, 0 or die "can't truncate $file"; 117 for my $k (keys %taken) { 118 print FILE $k . ' ' . $taken{$k} . "\n"; 119 } 120 } 121 close FILE; 122 flock SEM, LOCK_UN or warn "can't unlock $file.sem"; 123 close SEM; 124 $mtr_unique_assigned_ids{$ret} = $file if defined $ret; 125 return $ret; 126} 127 128# 129# Require a unique ID like above, but sleep if no ID can be 130# obtained immediately. 131# 132sub mtr_require_unique_id_and_wait($$$) { 133 my $ret = mtr_require_unique_id($_[0],$_[1],$_[2]); 134 while(! defined $ret) { 135 sleep 30; 136 $ret = mtr_require_unique_id($_[0],$_[1],$_[2]); 137 print "Waiting for unique id to become available...\n" unless $ret; 138 } 139 return $ret; 140} 141 142# 143# Release a unique ID. 144# 145sub mtr_release_unique_id($$) { 146 my $file = shift; 147 my $myid = shift; 148 149 if(eval("readlink '$file'") || eval("readlink '$file.sem'")) { 150 die 'lock file is a symbolic link'; 151 } 152 153 open SEM, ">", "$file.sem" or die "can't write to $file.sem"; 154 flock SEM, LOCK_EX or die "can't lock $file.sem"; 155 156 if(eval("readlink '$file'") || eval("readlink '$file.sem'")) { 157 die 'lock file is a symbolic link'; 158 } 159 160 if(! -e $file) { 161 open FILE, ">", $file or die "can't create $file"; 162 close FILE; 163 } 164 open FILE, "+<", $file or die "can't open $file"; 165 select undef,undef,undef,0.2; 166 seek FILE, 0, 0; 167 my %taken = (); 168 while(<FILE>) { 169 chomp; 170 my ($id, $pid) = split / /; 171 $taken{$id} = $pid; 172 } 173 delete $taken{$myid}; 174 seek FILE, 0, 0; 175 truncate FILE, 0 or die "can't truncate $file"; 176 for my $k (keys %taken) { 177 print FILE $k . ' ' . $taken{$k} . "\n"; 178 } 179 close FILE; 180 flock SEM, LOCK_UN or warn "can't unlock $file.sem"; 181 close SEM; 182 delete $mtr_unique_assigned_ids{$myid}; 183} 184 1851; 186 187