X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=perl%2FAmanda%2FRecovery%2FPlanner.pm;h=22809beeee465a90f19a82b9342796500c9359f1;hb=949b8910a5e23c4285d0b1aedacfc82a14dc97a5;hp=a3100623c536562dc4f363ce0af3f9a223557f37;hpb=c6f0a88c567f8536c498f554285aed1f8150da18;p=debian%2Famanda diff --git a/perl/Amanda/Recovery/Planner.pm b/perl/Amanda/Recovery/Planner.pm index a310062..22809be 100644 --- a/perl/Amanda/Recovery/Planner.pm +++ b/perl/Amanda/Recovery/Planner.pm @@ -1,4 +1,4 @@ -# Copyright (c) 2010 Zmanda, Inc. All Rights Reserved. +# Copyright (c) 2010-2012 Zmanda, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License version 2.1 as @@ -395,61 +395,121 @@ sub make_plan_from_filelist { unless exists $params{$rq_param}; } - # This is similarly tricky - in this case, we search for dumps matching - # both the dumpspec and the labels, filter that down to just the parts we - # want, and then check that only one dump remains. Then we look up that - # dump. - - my @labels; - my %files; - my @filelist = @{$params{'filelist'}}; - while (@filelist) { - my $label = shift @filelist; - push @labels, $label; - $files{$label} = shift @filelist; - } + my $steps = define_steps + cb_ref => \$params{'plan_cb'}; - my @parts = Amanda::DB::Catalog::get_parts( - $params{'dumpspec'}? (dumpspecs => [ $params{'dumpspec'} ]) : (), - labels => [ @labels ]); + step get_inventory => sub { + if (defined $params{'chg'} and $params{'chg'}->have_inventory()) { + return $params{'chg'}->inventory( inventory_cb => $steps->{'got_inventory'}); + } else { + return $steps->{'got_inventory'}->(undef, undef); + } + }; + step got_inventory => sub { + my ($err, $inventory) = @_; + + # This is similarly tricky - in this case, we search for dumps matching + # both the dumpspec and the labels, filter that down to just the parts we + # want, and then check that only one dump remains. Then we look up that + # dump. + + my @labels; + my %files; + my @filelist = @{$params{'filelist'}}; + while (@filelist) { + my $label = shift @filelist; + push @labels, $label; + $files{$label} = shift @filelist; + } - # filter down to the parts that match filelist (using %files) - @parts = grep { - my $filenum = $_->{'filenum'}; - grep { $_ == $filenum } @{$files{$_->{'label'}}}; - } @parts; + my @parts = Amanda::DB::Catalog::get_parts( + $params{'dumpspec'}? (dumpspecs => [ $params{'dumpspec'} ]) : (), + labels => [ @labels ]); - # extract the dumps, using a hash (on the perl identity of the dump) to - # ensure uniqueness - my %dumps = map { my $d = $_->{'dump'}; ($d, $d) } @parts; - my @dumps = values %dumps; + # filter down to the parts that match filelist (using %files) + @parts = grep { + my $filenum = $_->{'filenum'}; + grep { $_ == $filenum } @{$files{$_->{'label'}}}; + } @parts; - if (!@dumps) { - return $params{'plan_cb'}->( + # extract the dumps, using a hash (on the perl identity of the dump) to + # ensure uniqueness + my %dumps = map { my $d = $_->{'dump'}; ($d, $d) } @parts; + my @dumps = values %dumps; + + if (!@dumps) { + return $params{'plan_cb'}->( "Specified file list does not match dumpspec"); - } elsif (@dumps > 1) { - return $params{'plan_cb'}->( - "Specified file list matches multiple dumps; cannot continue recovery"); - } + } elsif (@dumps > 1) { + # Check if they are all for the same dump + my $dump_timestamp = $dumps[0]->{'dump_timestamp'}; + my $hostname = $dumps[0]->{'hostname'}; + my $diskname = $dumps[0]->{'diskname'}; + my $level = $dumps[0]->{'level'}; + my $orig_kb = $dumps[0]->{'orig_kb'}; + + foreach my $dump (@dumps) { + if ($dump_timestamp != $dump->{'dump_timestamp'} || + $hostname ne $dump->{'hostname'} || + $diskname ne $dump->{'diskname'} || + $level != $dump->{'level'} || + $orig_kb != $dump->{'orig_kb'}) { + return $params{'plan_cb'}->( + "Specified file list matches multiple dumps; cannot continue recovery"); + } + } - # now, because of the weak linking used by Amanda::DB::Catalog, we need to - # re-query for this dump. If we don't do this, the parts will all be - # garbage-collected when we hand back the plan. This is, chartiably, "less than - # ideal". Note that this has the side-effect of filling in any parts of the - # dump that were missing from the filelist. - @dumps = Amanda::DB::Catalog::get_dumps( - hostname => $dumps[0]->{'hostname'}, - diskname => $dumps[0]->{'diskname'}, - level => $dumps[0]->{'level'}, - dump_timestamp => $dumps[0]->{'dump_timestamp'}, - write_timestamp => $dumps[0]->{'write_timestamp'}, - dumpspecs => $params{'dumpspecs'}); - - # sanity check - die unless @dumps; - $self->{'dumps'} = [ $dumps[0] ]; + # I would prefer the Planner to return alternate dump and the Clerk + # choose which one to use + if (defined $inventory) { + for my $dump (@dumps) { + my $all_part_found = 0; + my $part_found = 1; + for my $part (@{$dump->{'parts'}}) { + next if !defined $part; + my $found = 0; + foreach my $sl (@$inventory) { + if (defined $sl->{'label'} and + $sl->{'label'} eq $part->{'label'}) { + $found = 1; + last; + } + } + if ($found == 0) { + $part_found = 0; + last; + } + } + if ($part_found == 1) { + @dumps = $dumps[0]; + last; + } + } + # the first one will be used + } else { + # will uses the first dump. + } + } - Amanda::MainLoop::call_later($params{'plan_cb'}, undef, $self); + # now, because of the weak linking used by Amanda::DB::Catalog, we need to + # re-query for this dump. If we don't do this, the parts will all be + # garbage-collected when we hand back the plan. This is, chartiably, "less + # than ideal". Note that this has the side-effect of filling in any parts of + # the dump that were missing from the filelist. + @dumps = Amanda::DB::Catalog::get_dumps( + hostname => $dumps[0]->{'hostname'}, + diskname => $dumps[0]->{'diskname'}, + level => $dumps[0]->{'level'}, + dump_timestamp => $dumps[0]->{'dump_timestamp'}, + write_timestamp => $dumps[0]->{'write_timestamp'}, + dumpspecs => $params{'dumpspecs'}); + + # sanity check + confess "no dumps" unless @dumps; + $self->{'dumps'} = [ $dumps[0] ]; + + Amanda::MainLoop::call_later($params{'plan_cb'}, undef, $self); + }; } sub split_dumps_per_part {