-# 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
=head1 OVERVIEW
-This package is the counterpart to L<Amanda::Recovery::Scribe>, and handles
+This package is the counterpart to L<Amanda::Taper::Scribe>, and handles
re-assembling dumpfiles from multiple parts, possibly distributed over several
volumes.
C<Amanda::Recovery::Clerk::Feedback>, which implements no-op versions of all of
the methods.
-The C<notif_part> method is called just before each part is restored, and is
+The C<clerk_notif_part> method is called just before each part is restored, and is
given the label, filenum, and header. Its return value, if any, is ignored.
-Similarly, C<notif_holding> is called for a holding-disk recovery and is given
-the holding filename and its header. Note that C<notif_holding> is called
+Similarly, C<clerk_notif_holding> is called for a holding-disk recovery and is given
+the holding filename and its header. Note that C<clerk_notif_holding> is called
before the C<xfer_src_cb>, since data will begin flowing from a holding disk
immediately when the transfer is started.
use base 'Amanda::Recovery::Clerk::Feedback';
- sub part_notif {
+ sub clerk_notif_part {
my $self = shift;
my ($label, $filenum, $hdr) = @_;
print "restoring part ", $hdr->{'partnum'},
my $self = shift;
my %params = @_;
- for my $rq_param qw(dump xfer_src_cb) {
+ for my $rq_param (qw(dump xfer_src_cb)) {
croak "required parameter '$rq_param' missing"
unless exists $params{$rq_param};
}
- die "Clerk is already busy" if $self->{'xfer_state'};
+ confess "Clerk is already busy" if $self->{'xfer_state'};
# set up a new xfer_state
my $xfer_state = $self->{'xfer_state'} = {
my %params = @_;
$self->dbg("starting recovery");
- for my $rq_param qw(xfer recovery_cb) {
+ for my $rq_param (qw(xfer recovery_cb)) {
croak "required parameter '$rq_param' missing"
unless exists $params{$rq_param};
}
- die "no xfer is in progress" unless $self->{'xfer_state'};
- die "get_xfer_src has not finished"
+ confess "no xfer is in progress" unless $self->{'xfer_state'};
+ confess "get_xfer_src has not finished"
if defined $self->{'xfer_state'}->{'xfer_src_cb'};
my $xfer_state = $self->{'xfer_state'};
sub quit {
my $self = shift;
my %params = @_;
+ my $finished_cb = $params{'finished_cb'};
- die "Cannot quit a Clerk while a transfer is in progress"
+ confess "Cannot quit a Clerk while a transfer is in progress"
if $self->{'xfer_state'};
- # if we have a reservation, we need to release it; otherwise, we can
- # just call finished_cb
- if ($self->{'current_res'}) {
- $self->{'current_dev'}->finish();
- $self->{'current_res'}->release(finished_cb => $params{'finished_cb'});
- } else {
- $params{'finished_cb'}->();
- }
+ my $steps = define_steps
+ cb_ref => \$finished_cb,
+ finalize => sub { $self->{'scan'}->quit() if defined $self->{'scan'} };
+
+ step release => sub {
+ # if we have a reservation, we need to release it; otherwise, we can
+ # just call finished_cb
+ if ($self->{'current_res'}) {
+ $self->{'current_dev'}->finish();
+ $self->{'current_res'}->release(finished_cb => $finished_cb);
+ } else {
+ $finished_cb->();
+ }
+ };
}
sub _xmsg_ready {
my $next_label = $xfer_state->{'next_part'}->{'label'};
my $next_filenum = $xfer_state->{'next_part'}->{'filenum'};
- die "read incorrect filenum"
+ confess "read incorrect filenum"
unless $next_filenum == $msg->{'fileno'};
$self->dbg("done reading file $next_filenum on '$next_label'");
return $xfer_state->{'recovery_cb'}->(
result => $result,
errors => $xfer_state->{'errors'},
+ bytes_read => $xfer_state->{'xfer_src'}->get_bytes_read()
);
}
# first, see if anything remains to be done
if (!exists $xfer_state->{'dump'}{'parts'}[$xfer_state->{'next_part_idx'}]) {
# this should not happen until the xfer is started..
- die "xfer should be running already"
+ confess "xfer should be running already"
unless $xfer_state->{'xfer'};
# tell the source to generate EOF
} else {
# notify caller of the part
- $self->{'feedback'}->notif_part($next_label, $next_filenum, $on_vol_hdr);
+ $self->{'feedback'}->clerk_notif_part($next_label, $next_filenum, $on_vol_hdr);
# start the part
$self->dbg("reading file $next_filenum on '$next_label'");
return $steps->{'handle_error'}->();
}
+ # remove CONT_FILENAME from the header, since it's not needed anymore
+ $on_disk_hdr->{'cont_filename'} = '';
+
if (!$self->_header_expected($on_disk_hdr)) {
# _header_expected already pushed an error message or two
return $steps->{'handle_error'}->();
$xfer_state->{'xfer_src_ready'} = 1;
# notify caller of the part, *before* xfer_src_cb is called!
- $self->{'feedback'}->notif_holding($next_filename, $on_disk_hdr);
+ $self->{'feedback'}->clerk_notif_holding($next_filename, $on_disk_hdr);
$self->dbg("successfully located holding file for recovery");
$cb->(undef, $on_disk_hdr, $xfer_state->{'xfer_src'}, 0);
};
}
+sub _zeropad {
+ my ($timestamp) = @_;
+ if (length($timestamp) == 8) {
+ return $timestamp."000000";
+ }
+ return $timestamp;
+}
+
sub _header_expected {
my $self = shift;
my ($on_vol_hdr) = @_;
push @errs, "got disk '$on_vol_hdr->{disk}'; " .
"expected '$next_part->{dump}->{diskname}'";
}
- if ($on_vol_hdr->{'datestamp'} ne $next_part->{'dump'}->{'dump_timestamp'}) {
+ # zeropad the datestamps before comparing them, to avoid any compliations
+ # from usetimestamps=0
+ if (_zeropad($on_vol_hdr->{'datestamp'})
+ ne _zeropad($next_part->{'dump'}->{'dump_timestamp'})) {
push @errs, "got datestamp '$on_vol_hdr->{datestamp}'; " .
"expected '$next_part->{dump}->{dump_timestamp}'";
}
return bless {}, shift;
}
-sub notif_part { }
+sub clerk_notif_part { }
-sub notif_holding { }
+sub clerk_notif_holding { }
1;