~drizzle-trunk/drizzle/development

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