1 # Copyright (c) 2010-2012 Zmanda, Inc. All Rights Reserved.
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.
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
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
17 # Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20 package Amanda::Taper::Scan::oldest;
24 Amanda::Taper::Scan::oldest
28 This package implements the "oldest" taperscan algorithm. See
29 C<amanda-taperscan(7)>.
35 use base qw( Amanda::ScanInventory Amanda::Taper::Scan );
41 use base qw(Exporter);
42 our @EXPORT_OK = qw($DEFAULT_CHANGER);
46 use Amanda::Device qw( :constants );
47 use Amanda::Debug qw( debug );
50 use Amanda::Interactivity;
51 use Amanda::Taper::Scan::traditional;
53 our $DEFAULT_CHANGER = {};
59 my $chg = $params{'changer'};
61 $chg = Amanda::Changer->new();
62 $params{'changer'} = $chg;
64 if (!$chg->have_inventory()) {
65 return Amanda::Taper::Scan::traditional->new(%params);
67 my $self = Amanda::ScanInventory->new(%params);
68 return bless ($self, $class);
73 return $self->oldest_reusable_volume();
76 sub first_reusable_label {
81 for my $tle (@{$self->{'tapelist'}->{'tles'}}) {
82 $label = $tle->{'label'} if $self->is_reusable_volume(label => $tle->{'label'});
90 my $tles = $self->{'tapelist'}->{tles};
91 my $label = $tles->[0]->{'label'};
96 my $inventory = shift;
103 my $first_new_volume;
109 my $label = $self->most_prefered();
110 $self->{'most_prefered_label'} = $label;
112 for my $i (0..(scalar(@$inventory)-1)) {
113 my $sl = $inventory->[$i];
114 if ($sl->{current}) {
117 next if $seen->{$sl->{slot}} and (!$res || $res->{'this_slot'} ne $sl->{'slot'});
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'})) {
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;
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;
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;
159 $unknown = $first_unknown if !defined $unknown;
160 $new_volume = $first_new_volume if !defined $new_volume;
162 my $first_label = $self->first_reusable_label();
163 my $last_label = $self->last_use_label();
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'};
174 for my $sl (@new_labeled) {
175 $new_labeled = $sl if !defined $new_labeled or
177 $sl->{'label'} lt $new_labeled->{'label'}) or
179 $sl->{'label'} gt $last_label and
180 $sl->{'label'} lt $new_labeled->{'label'}) or
182 $sl->{'label'} gt $last_label and
183 $new_labeled->{'label'} lt $last_label) or
185 $new_labeled->{'label'} lt $last_label and
186 $sl->{'label'} lt $new_labeled->{'label'});
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'}));
201 if ($new_labeled && $self->{'scan_conf'}->{'new_labeled'} eq 'soon') {
203 } elsif ($new_volume && $self->{'scan_conf'}->{'new_volume'} eq 'soon') {
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'}))) {
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'}))) {
231 } elsif (defined $most_prefered) {
232 $use = $most_prefered;
233 } elsif (defined $reusable) {
235 } elsif ($new_labeled and $self->{'scan_conf'}->{'new_labeled'} eq 'last') {
237 } elsif ($new_volume and $self->{'scan_conf'}->{'new_volume'} eq 'last') {
242 if (defined $res and $res->{'this_slot'} eq $use->{'slot'}) {
243 return (Amanda::ScanInventory::SCAN_DONE);
245 return (Amanda::ScanInventory::SCAN_LOAD,
248 } elsif ($unknown and $self->{'scan_conf'}->{'scan'}) {
249 return (Amanda::ScanInventory::SCAN_LOAD,
251 } elsif ($self->{'scan_conf'}->{'ask'}) {
252 return (Amanda::ScanInventory::SCAN_ASK_POLL);
254 return (Amanda::ScanInventory::SCAN_FAIL);