Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Taper / Scan / oldest.pm
1 # Copyright (c) 2010-2012 Zmanda, Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 # for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19
20 package Amanda::Taper::Scan::oldest;
21
22 =head1 NAME
23
24 Amanda::Taper::Scan::oldest
25
26 =head1 SYNOPSIS
27
28 This package implements the "oldest" taperscan algorithm.  See
29 C<amanda-taperscan(7)>.
30
31 =cut
32
33 use strict;
34 use warnings;
35 use base qw( Amanda::ScanInventory Amanda::Taper::Scan );
36 use Amanda::Tapelist;
37 use Carp;
38 use POSIX ();
39 use Data::Dumper;
40 use vars qw( @ISA );
41 use base qw(Exporter);
42 our @EXPORT_OK = qw($DEFAULT_CHANGER);
43
44 use Amanda::Paths;
45 use Amanda::Util;
46 use Amanda::Device qw( :constants );
47 use Amanda::Debug qw( debug );
48 use Amanda::Changer;
49 use Amanda::MainLoop;
50 use Amanda::Interactivity;
51 use Amanda::Taper::Scan::traditional;
52
53 our $DEFAULT_CHANGER = {};
54
55 sub new {
56     my $class = shift;
57     my %params = @_;
58
59     my $chg = $params{'changer'};
60     if (!defined $chg) {
61         $chg = Amanda::Changer->new();
62         $params{'changer'} = $chg;
63     }
64     if (!$chg->have_inventory()) {
65         return Amanda::Taper::Scan::traditional->new(%params);
66     }
67     my $self = Amanda::ScanInventory->new(%params);
68     return bless ($self, $class);
69 }
70
71 sub most_prefered {
72     my $self = shift;
73     return $self->oldest_reusable_volume();
74 }
75
76 sub first_reusable_label {
77     my $self = shift;
78
79     my $label;
80
81     for my $tle (@{$self->{'tapelist'}->{'tles'}}) {
82         $label = $tle->{'label'} if $self->is_reusable_volume(label => $tle->{'label'});
83     }
84     return $label;
85 }
86
87 sub last_use_label {
88     my $self = shift;
89
90     my $tles = $self->{'tapelist'}->{tles};
91     my $label = $tles->[0]->{'label'};
92 }
93
94 sub analyze {
95     my $self = shift;
96     my $inventory  = shift;
97     my $seen  = shift;
98     my $res = shift;
99
100     my $most_prefered;
101     my @reusable;
102     my @new_labeled;
103     my $first_new_volume;
104     my $new_volume;
105     my @new_volume;
106     my $first_unknown;
107     my $unknown;
108     my $current;
109     my $label = $self->most_prefered();
110     $self->{'most_prefered_label'} = $label;
111
112     for my $i (0..(scalar(@$inventory)-1)) {
113         my $sl = $inventory->[$i];
114         if ($sl->{current}) {
115             $current = $sl;
116         }
117         next if $seen->{$sl->{slot}} and (!$res || $res->{'this_slot'} ne $sl->{'slot'});
118
119         if (!defined $sl->{'state'} ||
120             $sl->{'state'} == Amanda::Changer::SLOT_UNKNOWN) {
121             $first_unknown = $sl if !$first_unknown;
122             $unknown = $sl if $current && !$unknown;
123         } elsif ($sl->{'state'} == Amanda::Changer::SLOT_EMPTY) {
124         } elsif (defined $sl->{'label'}) {
125             if ($label && $sl->{'label'} eq $label) {
126                 $most_prefered = $sl;
127             } elsif ($self->is_reusable_volume(label => $sl->{'label'})) {
128                 push @reusable, $sl;
129             } else {
130                 my $vol_tle = $self->{'tapelist'}->lookup_tapelabel($sl->{'label'});
131                 if ($vol_tle && $sl->{'label'} =~ /$self->{'labelstr'}/) {
132                     if ($vol_tle->{'datestamp'} eq '0') {
133                         push @new_labeled, $sl;
134                     }
135                 } elsif ($self->volume_is_labelable($sl)) {
136                     $sl->{'label'} = $self->{'chg'}->make_new_tape_label(
137                                         barcode => $sl->{'barcode'},
138                                         slot => $sl->{'slot'},
139                                         meta => $sl->{'meta'});
140                     $first_new_volume = $sl if !$first_new_volume;
141                     $new_volume = $sl if $current && !$new_volume;
142                     push @new_volume, $sl;
143                 }
144             }
145         } elsif ($self->volume_is_labelable($sl)) {
146             $sl->{'label'} = $self->{'chg'}->make_new_tape_label(
147                                         barcode => $sl->{'barcode'},
148                                         slot => $sl->{'slot'},
149                                         meta => $sl->{'meta'});
150             $first_new_volume = $sl if !$first_new_volume;
151             $new_volume = $sl if $current && !$new_volume;
152             push @new_volume, $sl;
153         } elsif (!defined($sl->{device_status}) && !defined($sl->{label})) {
154             $first_unknown = $sl if !$first_unknown;
155             $unknown = $sl if $current && !$unknown;
156         } else {
157         }
158     }
159     $unknown = $first_unknown if !defined $unknown;
160     $new_volume = $first_new_volume if !defined $new_volume;
161
162     my $first_label = $self->first_reusable_label();
163     my $last_label = $self->last_use_label();
164
165     my $reusable;
166     for my $sl (@reusable) {
167         my $tle = $self->{'tapelist'}->lookup_tapelabel($sl->{'label'});
168         $sl->{'datestamp'} = $tle->{'datestamp'};
169         $reusable = $sl if !defined $reusable or
170                            $sl->{'datestamp'} < $reusable->{'datestamp'};
171     }
172
173     my $new_labeled;
174     for my $sl (@new_labeled) {
175         $new_labeled = $sl if !defined $new_labeled or
176                               (!$last_label and
177                                $sl->{'label'} lt $new_labeled->{'label'}) or
178                               ($last_label and
179                                $sl->{'label'} gt $last_label and
180                                $sl->{'label'} lt $new_labeled->{'label'}) or
181                               ($last_label and
182                                $sl->{'label'} gt $last_label and
183                                $new_labeled->{'label'} lt $last_label) or
184                               ($last_label and
185                                $new_labeled->{'label'} lt $last_label and
186                                $sl->{'label'} lt $new_labeled->{'label'});
187     }
188
189     for my $sl (@new_volume) {
190         $new_volume = $sl if defined $last_label and
191                              $new_volume->{'label'} ne $sl->{'label'} and
192                              (($sl->{'label'} gt $last_label and
193                                $sl->{'label'} lt $new_volume->{'label'}) or
194                               ($sl->{'label'} gt $last_label and
195                                $new_volume->{'label'} lt $last_label) or
196                               ($new_volume->{'label'} lt $last_label and
197                                $sl->{'label'} lt $new_volume->{'label'}));
198     }
199
200     my $use;
201     if ($new_labeled && $self->{'scan_conf'}->{'new_labeled'} eq 'soon') {
202         $use = $new_labeled;
203     } elsif ($new_volume && $self->{'scan_conf'}->{'new_volume'} eq 'soon') {
204         $use = $new_volume;
205     } elsif ($new_labeled &&
206               $self->{'scan_conf'}->{'new_labeled'} eq 'order' and
207               (!$label || !$first_label || !$last_label || !$most_prefered or
208                ($last_label and $most_prefered and
209                 $new_labeled->{'label'} gt $last_label and
210                 $new_labeled->{'label'} lt $most_prefered->{'label'}) or
211                ($last_label and $most_prefered and
212                 $new_labeled->{'label'} gt $last_label and
213                 $most_prefered->{'label'} lt $last_label) or
214                ($first_label and $most_prefered and
215                 $new_labeled->{'label'} lt $first_label and
216                 $new_labeled->{'label'} lt $most_prefered->{'label'}))) {
217         $use = $new_labeled;
218     } elsif ($new_volume and
219              $self->{'scan_conf'}->{'new_volume'} eq 'order' and
220              (!$label || !$first_label || !$last_label || !$most_prefered or
221               ($last_label and $most_prefered and
222                $new_volume->{'label'} gt $last_label and
223                $new_volume->{'label'} lt $most_prefered->{'label'}) or
224               ($last_label and $most_prefered and
225                $new_volume->{'label'} gt $last_label and
226                $most_prefered->{'label'} lt $last_label) or
227               ($first_label and $most_prefered and
228                $new_volume->{'label'} lt $first_label and
229                $new_volume->{'label'} lt $most_prefered->{'label'}))) {
230         $use = $new_volume;
231     } elsif (defined $most_prefered) {
232         $use = $most_prefered;
233     } elsif (defined $reusable) {
234         $use = $reusable;
235     } elsif ($new_labeled and $self->{'scan_conf'}->{'new_labeled'} eq 'last') {
236         $use = $new_labeled;
237     } elsif ($new_volume and $self->{'scan_conf'}->{'new_volume'} eq 'last') {
238         $use = $new_volume;
239     }
240
241     if ($use) {
242         if (defined $res and $res->{'this_slot'} eq $use->{'slot'}) {
243             return (Amanda::ScanInventory::SCAN_DONE);
244         } else {
245             return (Amanda::ScanInventory::SCAN_LOAD,
246                     $use->{'slot'});
247         }
248     } elsif ($unknown and $self->{'scan_conf'}->{'scan'}) {
249         return (Amanda::ScanInventory::SCAN_LOAD,
250                 $unknown->{'slot'});
251     } elsif ($self->{'scan_conf'}->{'ask'}) {
252         return (Amanda::ScanInventory::SCAN_ASK_POLL);
253     } else {
254         return (Amanda::ScanInventory::SCAN_FAIL);
255     }
256 }
257
258 1;