don't chew CPU on clusters with many devices.
[MogileFS-Server.git] / t / 00-startup.t
blobfd9b5e00ec636988accc9d26963706c271051365
1 # -*-perl-*-
3 use strict;
4 use warnings;
5 use Test::More;
6 use FindBin qw($Bin);
8 use MogileFS::Server;
9 use MogileFS::Util qw(error_code);
10 use MogileFS::Test;
12 find_mogclient_or_skip();
14 # use mogadm to init it,
15 # mogstored on temp dir,
16 # register mogstored temp dir,
17 # mogilefsd startup,
18 # add file,
19 # etc
21 my $sto = eval { temp_store(); };
22 if ($sto) {
23     plan tests => 63;
24 } else {
25     plan skip_all => "Can't create temporary test database: $@";
26     exit 0;
29 my $dbh = $sto->dbh;
30 my $rv;
32 use File::Temp;
33 my %mogroot;
34 $mogroot{1} = File::Temp::tempdir( CLEANUP => 1 );
35 $mogroot{2} = File::Temp::tempdir( CLEANUP => 1 );
36 $mogroot{3} = File::Temp::tempdir( CLEANUP => 1 );
37 my $dev2host = { 1 => 1, 2 => 1,
38                  3 => 2, 4 => 2,
39                  5 => 3, 6 => 3, };
40 foreach (sort { $a <=> $b } keys %$dev2host) {
41     my $root = $mogroot{$dev2host->{$_}};
42     mkdir("$root/dev$_") or die "Failed to create dev$_ dir: $!";
45 my $ms1 = create_mogstored("127.0.1.1", $mogroot{1});
46 ok($ms1, "got mogstored1");
47 my $ms2 = create_mogstored("127.0.1.2", $mogroot{2});
48 ok($ms2, "got mogstored2");
50 while (! -e "$mogroot{1}/dev1/usage" &&
51        ! -e "$mogroot{2}/dev4/usage") {
52     print "Waiting on usage...\n";
53     sleep 1;
56 my $tmptrack = create_temp_tracker($sto);
57 ok($tmptrack);
59 my $mogc = MogileFS::Client->new(
60                                  domain => "testdom",
61                                  hosts  => [ "127.0.0.1:7001" ],
62                                  );
63 my $be = $mogc->{backend}; # gross, reaching inside of MogileFS::Client
65 my $lasttime = 1167609600; # Mon Jan  1 00:00:00 UTC 2007
66 ok(try_for(3, sub {
67     my $timestamp = $dbh->selectrow_array("SELECT ".$sto->unix_timestamp);
68     # FIXME: Some databases might be pedantic about the FROM
69     # but having it on others means that if the table has no rows
70     # we won't get any results!
71     my $rv = $timestamp > $lasttime;
72     $lasttime = $timestamp;
73     return $rv;
74 }), "Store provides sane unix_timestamp");
76 # test some basic commands to backend
77 ok($be->do_request("test", {}), "test ping worked");
78 ok(!$be->do_request("test", {crash => 1}), "crash didn't");
79 ok($be->do_request("test", {}), "test ping again worked");
82 ok($tmptrack->mogadm("domain", "add", "todie"), "created todie domain");
83 ok($tmptrack->mogadm("domain", "delete", "todie"), "delete todie domain");
84 ok(!$tmptrack->mogadm("domain", "delete", "todie"), "didn't delete todie domain again");
86 ok($tmptrack->mogadm("domain", "add", "testdom"), "created test domain");
87 ok($tmptrack->mogadm("class", "add", "testdom", "2copies", "--mindevcount=2"), "created 2copies class in testdom");
89 ok($tmptrack->mogadm("host", "add", "hostA", "--ip=127.0.1.1", "--status=alive"), "created hostA");
90 ok($tmptrack->mogadm("host", "add", "hostB", "--ip=127.0.1.2", "--status=alive"), "created hostB");
92 ok($tmptrack->mogadm("device", "add", "hostA", 1), "created dev1 on hostA");
93 ok($tmptrack->mogadm("device", "add", "hostA", 2), "created dev2 on hostA");
94 ok($tmptrack->mogadm("device", "add", "hostB", 3), "created dev3 on hostB");
95 ok($tmptrack->mogadm("device", "add", "hostB", 4), "created dev4 on hostB");
97 #ok($tmptrack->mogadm("device", "mark", "hostA", 1, "alive"), "dev1 alive");
98 #ok($tmptrack->mogadm("device", "mark", "hostA", 2, "alive"), "dev2 alive");
99 #ok($tmptrack->mogadm("device", "mark", "hostB", 3, "alive"), "dev3 alive");
100 #ok($tmptrack->mogadm("device", "mark", "hostB", 4, "alive"), "dev4 alive");
102 # wait for monitor
104     my $was = $be->{timeout};  # can't use local on phash :(
105     $be->{timeout} = 10;
106     ok($be->do_request("do_monitor_round", {}), "waited for monitor")
107         or die "Failed to wait for monitor";
108     $be->{timeout} = $was;
112     my $fh = $mogc->new_file('no_content', "2copies");
113     ok(close($fh), "closed file");
117     my $fh = $mogc->new_file('no_content', "2copies");
118     ok(close($fh), "closed file");
121 # wait for it to replicate
122 ok(try_for(10, sub {
123     my @urls = $mogc->get_paths("no_content");
124     my $nloc = @urls;
125     if ($nloc < 2) {
126         diag("no_content still only on $nloc devices");
127         return 0;
128     }
129     return 1;
130 }), "replicated to 2 paths");
132 ok(try_for(3, sub {
133     my $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
134     return $to_repl_rows == 0;
135 }), "no more files to replicate");
137 # quick delete test
138 ok($mogc->delete("no_content"), "deleted no_content")
139     or die "Error: " . $mogc->errstr;
141 # create two sample files
142 my $data = "My test file.\n" x 1024;
143 foreach my $k (qw(file1 file2)) {
144     my $fh = $mogc->new_file($k, "2copies");
145     ok($fh, "got filehandle") or
146         die "Error: " . $mogc->errstr;
147     print $fh $data;
148     ok(close($fh), "closed file");
151 # quick delete test
152 ok($mogc->delete("file2"), "deleted file2")
153     or die "Error: " . $mogc->errstr;
155 # verify we can't delete the domain now
156 ok(!$tmptrack->mogadm("domain", "delete", "testdom"), "can't delete domain in use");
158 # wait for it to replicate
159 my @urls;
160 ok(try_for(10, sub {
161     @urls = $mogc->get_paths("file1");
162     my $nloc = @urls;
163     if ($nloc < 2) {
164         diag("file1 still only on $nloc devices");
165         return 0;
166     }
167     return 1;
168 }), "replicated to 2 paths");
170 ok(try_for(3, sub {
171     my $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
172     return $to_repl_rows == 0;
173 }), "no more files to replicate");
175 my $p1 = MogPath->new($urls[0]);
176 my $p2 = MogPath->new($urls[1]);
177 isnt($p1->host, $p2->host, "host1 and host2 are different");
178 my $path1 = $mogroot{$dev2host->{$p1->device}} . $p1->path;
179 my $path2 = $mogroot{$dev2host->{$p2->device}} . $p2->path;
180 is(-s $path1, length($data), "right length on disk for path1");
181 is(-s $path2, length($data), "right length on disk for path2");
183 ok(unlink($path1), "deleted path $path1");
184 my $dead_url = $urls[0];
185 for (1..10) {
186     @urls = $mogc->get_paths("file1");
187     isnt($urls[0], $dead_url, "didn't return dead url first (try $_)");
190 ok($be->do_request("rename", {
191     from_key => "file1",
192     to_key   => "file1renamed",
193     domain   => "testdom",
194 }), "renamed file1 to file1renamed");
196 ok($be->do_request("delete", {
197     key    => "file1renamed",
198     domain => "testdom",
199 }), "deleted file1renamed");
201 # create a couple hundred files now
202 my $n_files = 100;
203 diag("Creating $n_files files...");
204 for my $n (1..$n_files) {
205     my $fh = $mogc->new_file("manyhundred_$n", "2copies")
206         or die "Failed to create manyhundred_$n: " . $mogc->errstr;
207     my $data = "File number $n.\n" x 512;
208     print $fh $data;
209     close($fh) or die "Failed to close manyhundred_$n";
210     diag("created $n/$n_files") if $n % 10 == 0;
212 pass("Created a ton of files");
214 # wait for replication to go down
216     my $iters = 30;
217     my $to_repl_rows;
218     while ($iters) {
219         $iters--;
220         $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
221         last if ! $to_repl_rows;
222         diag("Files to replicate: $to_repl_rows");
223         sleep 1;
224     }
225     die "Failed to replicate all $n_files files" if $to_repl_rows;
226     pass("Replicated all $n_files files");
229 # now let's delete a host, which should fail hard, because there are still devices attached to it
231     die "Can't delete an active host" if
232         $tmptrack->mogadm("host", "delete", "hostB");
233     pass("didn't delete hostB");
236 # create a new host and device, for when we start killing some devices
237 my $ms3 = create_mogstored("127.0.1.3", $mogroot{3});
238 ok($ms3, "got mogstored3");
239 ok($tmptrack->mogadm("host", "add", "hostC", "--ip=127.0.1.3", "--status=alive"), "created hostC");
240 ok($tmptrack->mogadm("device", "add", "hostC", 5), "created dev5 on hostC");
241 ok($tmptrack->mogadm("device", "add", "hostC", 6), "created dev6 on hostC");
243 # let it be discovered
244 sleep(3);  # FIXME: make an explicit "rescan" or "remonitor" job to mogilefsd, just for test suite
246 ok($tmptrack->mogadm("device", "mark", "hostB", 3, "dead"), "marked device B/3 dead");
247 ok($tmptrack->mogadm("device", "mark", "hostB", 4, "dead"), "marked device B/4 dead");
249 ok(try_for(40, sub {
250     my %has;
251     my $sth = $dbh->prepare("SELECT devid, COUNT(*) FROM file_on GROUP BY devid");
252     $sth->execute;
253     while (my ($devid, $ct) = $sth->fetchrow_array) {
254         $has{$devid} = $ct;
255     }
256     diag("Replication update: " . join(", ", map { "dev$_: " . sprintf("%3d", ($has{$_}||0)) } (1..6)));
257     return 0 if $has{3} || $has{4};
258     return $has{1} && $has{1} && $has{5} && $has{6};
259 }), "files replicated to hostC from hostB");
261 # kill hostB now
262 # hosts are no longer able to be nuked even if they have deleted devices.
263 # this saves us from some subtle bugs.
264 #ok($tmptrack->mogadm("host", "delete", "hostB"), "killed hostB");
266 # delete them all, see if they go away.
267 for my $n (1..$n_files) {
268     my $rv = $mogc->delete("manyhundred_$n")
269         or die "Failed to delete manyhundred_$n";
271 pass("deleted all $n_files files");
273 ok(try_for(25, sub {
274     my @files;
275     foreach my $hn (1, 3) {
276         my @lfiles = `find $mogroot{$hn} -type f -name '*.fid'`;
277         push @files, @lfiles;
278         diag("files on host $hn = " . scalar(@lfiles));
279     }
280     return @files == 0;
281 }), "and they're gone from filesystem");
283 foreach my $t (qw(file file_on file_to_delete)) {
284     ok(try_for(5, sub {
285         return $dbh->selectrow_array("SELECT COUNT(*) FROM $t") == 0;
286     }), "table $t is empty");
289 sub try_for {
290     my ($tries, $code) = @_;
291     for (1..$tries) {
292         return 1 if $code->();
293         sleep 1;
294     }
295     return 0;