/[BackupPC]/trunk/bin/BackupPC_incPartsUpdate
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/bin/BackupPC_incPartsUpdate

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 265 by dpavlin, Tue Dec 13 00:10:48 2005 UTC revision 312 by dpavlin, Sun Jan 29 15:54:10 2006 UTC
# Line 16  use Archive::Tar::Streamed; Line 16  use Archive::Tar::Streamed;
16  use Algorithm::Diff;  use Algorithm::Diff;
17  use Getopt::Std;  use Getopt::Std;
18  use File::Slurp;  use File::Slurp;
19    use File::Pid;
20    
21    =head1 NAME
22    
23    BackupPC_incPartsUpdate
24    
25    =head1 DESCRIPTION
26    
27    Create C<.tar.gz> increments on disk calling C<BackupPC_tarIncCreate>.
28    
29    Following options are supported (but all are optional):
30    
31    =over 4
32    
33    =item -h hostname
34    
35    Update parts for just single C<hostname>
36    
37    =item -c
38    
39    Force check for tar archives which exist on disk
40    
41    =item -d
42    
43    Turn debugging output
44    
45    =back
46    
47    =cut
48    
49    my %opt;
50    getopts("cdh:", \%opt );
51    
52    my $debug = $opt{d};
53    my $check = $opt{c} && print STDERR "NOTICE: tar archive check forced\n";
54    
55    my $pid_path = abs_path($0);
56    $pid_path =~ s/\W+/_/g;
57    
58    my $pidfile = new File::Pid({
59            file => "/tmp/$pid_path",
60    });
61    
62    if (my $pid = $pidfile->running ) {
63            die "$0 already running: $pid\n";
64    } elsif ($pidfile->pid ne $$) {
65            $pidfile->remove;
66            $pidfile = new File::Pid;
67    }
68    
69    print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
70    $pidfile->write;
71    
72  my $bpc = BackupPC::Lib->new || die "can't create BackupPC::Lib";  my $bpc = BackupPC::Lib->new || die "can't create BackupPC::Lib";
73  my %Conf = $bpc->Conf();  my %Conf = $bpc->Conf();
# Line 34  foreach my $c (qw/gzip md5sum/) { Line 86  foreach my $c (qw/gzip md5sum/) {
86          $bin->{$c} = which($c) || die "$0 needs $c, install it\n";          $bin->{$c} = which($c) || die "$0 needs $c, install it\n";
87  }  }
88    
 my %opt;  
 getopts("cd", \%opt );  
   
 my $debug = $opt{d};  
 my $check = $opt{c} && print STDERR "NOTICE: tar archive check forced\n";  
   
89  $|=1;  $|=1;
90    
91  my $start_t = time();  my $start_t = time();
# Line 84  sub get_backup_id($$$) { Line 130  sub get_backup_id($$$) {
130                  FROM backups                  FROM backups
131                  INNER JOIN shares       ON backups.shareID=shares.ID                  INNER JOIN shares       ON backups.shareID=shares.ID
132                  INNER JOIN hosts        ON backups.hostID = hosts.ID                  INNER JOIN hosts        ON backups.hostID = hosts.ID
133                  where hosts.name = ? and shares.name = ? and backups.num = ?                  WHERE hosts.name = ? and shares.name = ? and backups.num = ?
134          });          });
135          $sth->execute($host, $share, $num);          $sth->execute($host, $share, $num);
136          my ($id) = $sth->fetchrow_array;          my ($id) = $sth->fetchrow_array;
# Line 96  sub get_backup_id($$$) { Line 142  sub get_backup_id($$$) {
142          return $id;          return $id;
143  }  }
144    
145    sub backup_inc_deleted($) {
146            my $backup_id = shift;
147            my $sth_inc_deleted = $dbh->prepare(qq{
148                    update backups set
149                            inc_deleted = true
150                    where id = ?
151            });
152            $sth_inc_deleted->execute($backup_id);
153    }
154    
155  sub tar_check($$$$) {  sub tar_check($$$$) {
156          my ($host,$share,$num,$filename) = @_;          my ($host,$share,$num,$filename) = @_;
157    
158            my $t = time();
159            print curr_time, " check $host:$share#$num -> $filename";
160    
161            # depending on expected returned value this is used like:
162            # my $uncompress_size = get_gzip_size('/full/path/to.gz');
163            # my ($compress_size, $uncompress_size) = get_gzip_size('/path.gz');
164            sub get_gzip_size($) {
165                    my $filename = shift;
166                    die "file $filename problem: $!" unless (-r $filename);
167                    open(my $gzip, $bin->{gzip}." -l $filename |") || die "can't gzip -l $filename: $!";
168                    my $line = <$gzip>;
169                    chomp($line);
170                    $line = <$gzip> if ($line =~ /^\s+compressed/);
171    
172                    my ($comp, $uncomp) = (0,0);
173    
174                    if ($line =~ m/^\s+(\d+)\s+(\d+)\s+\d+\.\d+/) {
175                            if (wantarray) {
176                                    return [ $1, $2 ];
177                            } else {
178                                    return $2;
179                            }
180                    } else {
181                            die "can't find size in line: $line";
182                    }
183            }
184    
185          sub check_part {          sub check_part {
186                  my ($host, $share, $num, $part_nr, $tar_size, $size, $md5, $items) = @_;                  my ($host, $share, $num, $part_nr, $tar_size, $size, $md5, $items) = @_;
187                  my $backup_id = get_backup_id($host, $share, $num);                  my $backup_id = get_backup_id($host, $share, $num);
# Line 119  sub tar_check($$$$) { Line 201  sub tar_check($$$$) {
201                                  $row->{md5} eq $md5 &&                                  $row->{md5} eq $md5 &&
202                                  $row->{items} == $items                                  $row->{items} == $items
203                          );                          );
204                          print STDERR "# deleting invalid row $row->{id}\n" if ($opt{d});                          print ", deleting invalid backup_parts $row->{id}";
205                          $dbh->do(qq{ delete from backup_parts where id = $row->{id} });                          $dbh->do(qq{ delete from backup_parts where id = $row->{id} });
206                  }                  }
207                  print STDERR "# inserting new backup_part row\n";                  print ", inserting new";
208                  my $sth_insert = $dbh->prepare(qq{                  my $sth_insert = $dbh->prepare(qq{
209                          insert into backup_parts (                          insert into backup_parts (
210                                  backup_id,                                  backup_id,
# Line 138  sub tar_check($$$$) { Line 220  sub tar_check($$$$) {
220                  $dbh->commit;                  $dbh->commit;
221          }          }
222    
         if ($debug) {  
                 print STDERR " {{ CHECK: ${host}:${share}#${num} and $filename";  
         } else {  
                 print " check";  
         }  
   
223          my @tar_parts;          my @tar_parts;
224    
225          if (-d "$tar_dir/$filename") {          if (-d "$tar_dir/$filename") {
226                  print STDERR " multi-part" if ($opt{d});                  print ", multi-part";
227                  opendir(my $dir, "$tar_dir/$filename") || die "can't readdir $tar_dir/$filename: $!";                  opendir(my $dir, "$tar_dir/$filename") || die "can't readdir $tar_dir/$filename: $!";
228                  @tar_parts = map { my $p = $_; $p =~ s#^#${filename}/#; $p } grep { !/^\./ && !/md5/ && -f "$tar_dir/$filename/$_" } readdir($dir);                  @tar_parts = map { my $p = $_; $p =~ s#^#${filename}/#; $p } grep { !/^\./ && !/md5/ && -f "$tar_dir/$filename/$_" } readdir($dir);
229                  closedir($dir);                  closedir($dir);
# Line 162  sub tar_check($$$$) { Line 238  sub tar_check($$$$) {
238    
239          my $backup_part;          my $backup_part;
240    
241          print " reading";          print " reading" if ($opt{d});
242    
243          foreach my $tarfilename (@tar_parts) {          foreach my $tarfilename (@tar_parts) {
244    
245                  print STDERR " $tarfilename" if ($debug);                  print "\n\t- $tarfilename";
246    
247                  my $path = "$tar_dir/$tarfilename";                  my $path = "$tar_dir/$tarfilename";
                 my $md5_path = $path;  
                 $md5_path =~ s/\.tar\.gz$/.md5/ || die "can't create md5 filename from $md5_path";  
                 if (! -e $md5_path) {  
                         print ", creating md5";  
                         system( $bin->{md5sum} . " $path > $md5_path") == 0 or die "can't create md5 $path: $!";  
                 }  
248    
249                  my $md5 = read_file( $md5_path ) || die "can't read md5sum file $md5_path: $!";                  my $size = (stat( $path ))[7] || die "can't stat $path: $!";
                 $md5 =~ s#\s.*$##;  
250    
251                  my $part_nr = 1;                  if ($size > $Conf{MaxArchiveSize}) {
252                  $part_nr = $1 if ($tarfilename =~ m#/(\d+)\.tar\.gz#);                          print ", part bigger than media $size > $Conf{MaxArchiveSize}\n";
253                            return 0;
254                    }
255    
256                  my $size = (stat( "$tar_dir/$tarfilename" ))[7] || die "can't stat $tar_dir/$tarfilename";                  print ", $size bytes";
257    
258                  open(my $fh, "gzip -cd $tar_dir/$tarfilename |") or die "can't open $tar_dir/$tarfilename: $!";  
259                    open(my $fh, "gzip -cd $path |") or die "can't open $path: $!";
260                  binmode($fh);                  binmode($fh);
261                  my $tar = Archive::Tar::Streamed->new($fh);                  my $tar = Archive::Tar::Streamed->new($fh);
262    
263                  my $tar_size = 0;                  my $tar_size_inarc = 0;
264                  my $items = 0;                  my $items = 0;
265    
266                  while(my $entry = $tar->next) {                  while(my $entry = $tar->next) {
267                          push @tar_files, $entry->name;                          push @tar_files, $entry->name;
268                          $items++;                          $items++;
269                          $tar_size += $entry->size;                          $tar_size_inarc += $entry->size;
270    
271                            if ($tar_size_inarc > $Conf{MaxArchiveFileSize}) {
272                                    print ", part $tarfilename is too big $tar_size_inarc > $Conf{MaxArchiveFileSize}\n";
273                                    return 0;
274                            }
275    
276                  }                  }
277    
278                  if ($tar_size > $Conf{MaxArchiveFileSize}) {                  close($fh);
279                          print STDERR " part too big $tar_size > $Conf{MaxArchiveFileSize} }}" if ($debug);  
280                          $same = 0;                  print ", $items items";
281                          last;  
282                  } elsif ($size > $Conf{MaxArchiveSize}) {                  if ($tar_size_inarc == 0 && $items == 0) {
283                          print STDERR " part bigger than media $size > $Conf{MaxArchiveSize} }}" if ($debug);                          print ", EMPTY tar\n";
284                          $same = 0;  
285                          last;                          my $backup_id = get_backup_id($host, $share, $num);
286                            backup_inc_deleted( $backup_id );
287    
288                            $dbh->commit;
289    
290                            return 1;
291                  }                  }
292    
293                    my $tar_size = get_gzip_size( $path );
294    
295                    # real tar size is bigger because of padding    
296                    if ($tar_size_inarc > $tar_size) {
297                            print ", size of files in tar ($tar_size_inarc) bigger than whole tar ($tar_size)!\n";
298                            return 0;
299                    }
300    
301                    #
302                    # check if md5 exists, and if not, create one
303                    #
304    
305                    my $md5_path = $path;
306                    $md5_path =~ s/\.tar\.gz$/.md5/ || die "can't create md5 filename from $md5_path";
307                    if (! -e $md5_path || -z $md5_path) {
308                            print ", creating md5";
309                            system( $bin->{md5sum} . " $path > $md5_path") == 0 or die "can't create md5 $path: $!";
310                    } else {
311                            ## FIXME check if existing md5 is valid
312                    }
313    
314                    my $md5 = read_file( $md5_path ) || die "can't read md5sum file $md5_path: $!";
315                    $md5 =~ s#\s.*$##;
316    
317                    # extract part number from filename
318                    my $part_nr = 1;
319                    $part_nr = $1 if ($tarfilename =~ m#/(\d+)\.tar\.gz#);
320    
321                    #
322                    # finally, check if backup_parts table in database is valid
323                    #
324    
325                  check_part($host, $share, $num, $part_nr, $tar_size, $size, $md5, $items);                  check_part($host, $share, $num, $part_nr, $tar_size, $size, $md5, $items);
326          }          }
327    
# Line 214  sub tar_check($$$$) { Line 329  sub tar_check($$$$) {
329          return $same unless($same);          return $same unless($same);
330    
331          @tar_files = sort @tar_files;          @tar_files = sort @tar_files;
332          print STDERR " ",($#tar_files + 1), " files" if ($debug);          print "\n\t",($#tar_files + 1), " tar files";
   
         print STDERR ", database" if ($debug);  
333    
334          my $sth = $dbh->prepare(qq{          my $sth = $dbh->prepare(qq{
335                  SELECT path,type                  SELECT path,type
# Line 235  sub tar_check($$$$) { Line 348  sub tar_check($$$$) {
348                  push @db_files, $path;                  push @db_files, $path;
349          }          }
350    
351          print STDERR " ",($#db_files + 1), " files, diff" if ($debug);          print " ",($#db_files + 1), " database files, diff";
352    
353          @db_files = sort @db_files;          @db_files = sort @db_files;
354    
355          if ($#tar_files != $#db_files) {          if ($#tar_files != $#db_files) {
356                  $same = 0;                  $same = 0;
357                  print STDERR " NUMBER" if ($debug);                  print " NUMBER";
358          } else {          } else {
359                  my $diff = Algorithm::Diff->new(\@tar_files, \@db_files);                  my $diff = Algorithm::Diff->new(\@tar_files, \@db_files);
360                  while ( $diff->Next() ) {                  while ( $diff->Next() ) {
# Line 252  sub tar_check($$$$) { Line 365  sub tar_check($$$$) {
365                  }                  }
366          }          }
367    
368          print " ",($same ? 'ok' : 'DIFFERENT');          print " ",($same ? 'ok' : 'DIFFERENT'),
369          print STDERR " }} " if ($debug);                  ", dur: ",fmt_time(time() - $t), "\n";
370    
371          return $same;          return $same;
372  }  }
# Line 268  select Line 381  select
381          hosts.name as host,          hosts.name as host,
382          shares.name as share,          shares.name as share,
383          backups.num as num,          backups.num as num,
384            backups.date,
385          inc_size,          inc_size,
386          parts          parts,
387            count(backup_parts.backup_id) as backup_parts
388  from backups  from backups
389          join shares on backups.hostid = shares.hostid          join shares on backups.hostid = shares.hostid
390                  and shares.id = backups.shareid                  and shares.id = backups.shareid
391          join hosts on shares.hostid = hosts.id          join hosts on shares.hostid = hosts.id
392  where not inc_deleted          full outer join backup_parts on backups.id = backup_parts.backup_id
393    where not inc_deleted and backups.size > 0
394    group by backups.id, hosts.name, shares.name, backups.num, backups.date, inc_size, parts, backup_parts.backup_id
395  order by backups.date  order by backups.date
396    
397  } );  } );
# Line 283  $sth->execute(); Line 400  $sth->execute();
400  my $num_backups = $sth->rows;  my $num_backups = $sth->rows;
401  my $curr_backup = 1;  my $curr_backup = 1;
402    
403    if ($opt{h}) {
404            warn "making increments just for host $opt{h}\n";
405    }
406    
407  while (my $row = $sth->fetchrow_hashref) {  while (my $row = $sth->fetchrow_hashref) {
408    
409            if ($opt{h} && $row->{host} ne $opt{h}) {
410                    warn "skipped $row->{host}\n" if ($debug);
411                    next;
412            }
413    
414            $curr_backup++;
415    
416          my $tar_file = BackupPC::SearchLib::getGzipName($row->{'host'}, $row->{'share'}, $row->{'num'});          my $tar_file = BackupPC::SearchLib::getGzipName($row->{'host'}, $row->{'share'}, $row->{'num'});
417    
418          # this will return -1 if file doesn't exist          # this will return -1 if file doesn't exist
# Line 291  while (my $row = $sth->fetchrow_hashref) Line 420  while (my $row = $sth->fetchrow_hashref)
420    
421          print "# size: $size backup.size: ", $row->{inc_size},"\n" if ($opt{d});          print "# size: $size backup.size: ", $row->{inc_size},"\n" if ($opt{d});
422    
423          if ( $row->{'inc_size'} != -1 && $size != -1 && $row->{'inc_size'} == $size) {          if ( $row->{'inc_size'} != -1 && $size != -1 && $row->{'inc_size'} >= $size && $row->{parts} == $row->{backup_parts}) {
424                  if ($check) {                  if ($check) {
425                          tar_check($row->{'host'}, $row->{'share'}, $row->{'num'}, $tar_file) && next;                          tar_check($row->{'host'}, $row->{'share'}, $row->{'num'}, $tar_file) && next;
426                  } else {                  } else {
# Line 299  while (my $row = $sth->fetchrow_hashref) Line 428  while (my $row = $sth->fetchrow_hashref)
428                  }                  }
429          }          }
430    
431          print curr_time, " $curr_backup/$num_backups ", $row->{'host'}, ":", $row->{'share'}, " #", $row->{'num'}, " -> $tar_file";          print curr_time, " creating $curr_backup/$num_backups ", $row->{host}, ":", $row->{share}, " #", $row->{num},
432          $curr_backup++;                  " ", strftime('%Y-%m-%d', localtime($row->{date})), " -> $tar_file";
433    
434          my $t = time();          my $t = time();
435    
436          # re-create archive?          # re-create archive?
437          my $cmd = qq{ $tarIncCreate -h "$row->{'host'}" -s "$row->{'share'}" -n $row->{'num'} -f };          my $cmd = qq[ $tarIncCreate -h "$row->{host}" -s "$row->{share}" -n $row->{num} -f ];
438          print STDERR "## $cmd\n" if ($debug);          print STDERR "## $cmd\n" if ($debug);
439    
440          if (system($cmd) != 0) {          if (system($cmd) != 0) {
441                  print STDERR " FAILED";                  print STDERR " FAILED, marking this backup deleted";
442                    backup_inc_deleted( $row->{backup_id} );
443          }          }
444    
445          print ", dur: ",fmt_time(time() - $t), "\n";          print ", dur: ",fmt_time(time() - $t), "\n";

Legend:
Removed from v.265  
changed lines
  Added in v.312

  ViewVC Help
Powered by ViewVC 1.1.26