--- trunk/lib/BackupPC/SearchLib.pm 2005/09/22 09:27:17 127 +++ trunk/lib/BackupPC/SearchLib.pm 2005/12/12 20:59:58 259 @@ -8,6 +8,8 @@ use DateTime; use vars qw(%In $MyURL); use Time::HiRes qw/time/; +use XML::Writer; +use IO::File; my $on_page = 100; my $pager_pages = 10; @@ -68,10 +70,20 @@ $mm =~ s/\D//g; $dd =~ s/\D//g; + my $h = my $m = my $s = 0; + if ($suffix eq 'to') { + $h = 23; + $m = 59; + $s = 59; + } + my $dt = new DateTime( year => $yyyy, month => $mm, - day => $dd + day => $dd, + hour => $h, + minute => $m, + second => $s, ); print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n"; return $dt->epoch || 'NULL'; @@ -100,7 +112,7 @@ push @conditions, qq{ files.date >= $files_from } if ($files_from); push @conditions, qq{ files.date <= $files_to } if ($files_to); - print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions); + print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" and ",@conditions); push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'}); push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'}); @@ -108,6 +120,67 @@ return join(" and ", @conditions); } +my $sort_def = { + search => { + default => 'date_a', + sql => { + share_d => 'shares.name DESC', + share_a => 'shares.name ASC', + path_d => 'files.path DESC', + path_a => 'files.path ASC', + num_d => 'files.backupnum DESC', + num_a => 'files.backupnum ASC', + size_d => 'files.size DESC', + size_a => 'files.size ASC', + date_d => 'files.date DESC', + date_a => 'files.date ASC', + }, + est => { + share_d => 'sname STRD', + share_a => 'sname STRA', + path_d => 'filepath STRD', + path_a => 'filepath STRA', + num_d => 'backupnum NUMD', + num_a => 'backupnum NUMA', + size_d => 'size NUMD', + size_a => 'size NUMA', + date_d => 'date NUMD', + date_a => 'date NUMA', + } + }, burn => { + default => 'date_a', + sql => { + share_d => 'host DESC, share DESC', + share_a => 'host ASC, share ASC', + num_d => 'backupnum DESC', + num_a => 'backupnum ASC', + date_d => 'date DESC', + date_a => 'date ASC', + age_d => 'age DESC', + age_a => 'age ASC', + size_d => 'size DESC', + size_a => 'size ASC', + incsize_d => 'inc_size DESC', + incsize_a => 'inc_size ASC', + } + } +}; + +sub getSort($$$) { + my ($part,$type, $sort_order) = @_; + + die "unknown part: $part" unless ($sort_def->{$part}); + die "unknown type: $type" unless ($sort_def->{$part}->{$type}); + + $sort_order ||= $sort_def->{$part}->{'default'}; + + if (my $ret = $sort_def->{$part}->{$type}->{$sort_order}) { + return $ret; + } else { + # fallback to default sort order + return $sort_def->{$part}->{$type}->{ $sort_def->{$part}->{'default'} }; + } +} sub getFiles($) { my ($param) = @_; @@ -139,8 +212,10 @@ my $where = getWhere($param); $sql_where = " WHERE ". $where if ($where); + my $order = getSort('search', 'sql', $param->{'sort'}); + my $sql_order = qq{ - ORDER BY files.date + ORDER BY $order LIMIT $on_page OFFSET ? }; @@ -182,7 +257,7 @@ if ($use_hest =~ m#^http://#) { $index_node_url = $use_hest; } else { - $index_path = $TopDir . '/' . $index_path; + $index_path = $TopDir . '/' . $use_hest; $index_path =~ s#//#/#g; } return ($index_path, $index_node_url); @@ -239,7 +314,7 @@ # $cond->set_max( $offset + $on_page ); $cond->set_options( $HyperEstraier::Condition::SURE ); - $cond->set_order( 'date NUMA' ); + $cond->set_order( getSort('search', 'est', $param->{'sort'} ) ); # get the result of search my @res; @@ -270,7 +345,7 @@ } my $row; - foreach my $c (qw/fid hname sname backupnum fiilename filepath date type size/) { + foreach my $c (qw/fid hname sname backupnum filepath date type size/) { $row->{$c} = $doc->attr($c); } push @res, $row; @@ -288,29 +363,120 @@ $ret =~ s/\\h/$host/ge; $ret =~ s/\\s/$share/ge; $ret =~ s/\\n/$backupnum/ge; - + + $ret =~ s/__+/_/g; + return $ret; } -sub getBackupsNotBurned() { +sub get_tgz_size_by_name($) { + my $name = shift; + + my $tgz = $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'.$name; + + my $size = -1; + + if (-f "${tgz}.tar.gz") { + $size = (stat("${tgz}.tar.gz"))[7]; + } elsif (-d $tgz) { + opendir(my $dir, $tgz) || die "can't opendir $tgz: $!"; + my @parts = grep { !/^\./ && !/md5/ && -f "$tgz/$_" } readdir($dir); + $size = 0; + foreach my $part (@parts) { + $size += (stat("$tgz/$part"))[7] || die "can't stat $tgz/$part: $!"; + } + closedir $dir; + } else { + return -1; + } + + return $size; +} + +sub getGzipSize($$) +{ + my ($hostID, $backupNum) = @_; + my $sql; + my $dbh = get_dbh(); + + $sql = q{ + SELECT hosts.name as host, + shares.name as share, + backups.num as backupnum + FROM hosts, backups, shares + WHERE shares.id=backups.shareid AND + hosts.id =backups.hostid AND + hosts.id=? AND + backups.num=? + }; + my $sth = $dbh->prepare($sql); + $sth->execute($hostID, $backupNum); + + my $row = $sth->fetchrow_hashref(); + + return get_tgz_size_by_name( + getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'}) + ); +} + +sub getVolumes($) { + my $id = shift; + + my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize"; + + my $sth = $dbh->prepare(qq{ + select + size + from backup_parts + where backup_id = ? + order by part_nr asc + }); + + $sth->execute($id); + + my $cumulative_size = 0; + my $volumes = 1; + + while(my ($size) = $sth->fetchrow_array) { + if ($cumulative_size + $size > $max_archive_size) { + $volumes++; + $cumulative_size = $size; + } else { + $cumulative_size += $size; + } + } + + return ($volumes,$cumulative_size); +} + +sub getBackupsNotBurned($) { + my $param = shift; my $dbh = get_dbh(); - my $sql = q{ + my $order = getSort('burn', 'sql', $param->{'sort'}); + +print STDERR "## sort=". ($param->{'sort'} || 'no sort param') . " burn sql order: $order\n"; + + my $sql = qq{ SELECT backups.hostID AS hostID, hosts.name AS host, shares.name AS share, - backups.id AS backupnum, + backups.num AS backupnum, backups.type AS type, backups.date AS date, - backups.size AS size + date_part('epoch',now()) - backups.date as age, + backups.size AS size, + backups.id AS id, + backups.inc_size AS inc_size, + backups.parts AS parts FROM backups INNER JOIN shares ON backups.shareID=shares.ID INNER JOIN hosts ON backups.hostID = hosts.ID - LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id AND archive_backup.backup_id IS NULL - WHERE backups.size > 0 + LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id + WHERE backups.inc_size > 0 AND backups.inc_deleted is false AND archive_backup.backup_id IS NULL GROUP BY backups.hostID, hosts.name, @@ -320,82 +486,175 @@ backups.id, backups.type, backups.date, - backups.size - ORDER BY backups.date + backups.size, + backups.inc_size, + backups.parts + ORDER BY $order }; my $sth = $dbh->prepare( $sql ); my @ret; $sth->execute(); while ( my $row = $sth->fetchrow_hashref() ) { - $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) ); - $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024); - my (undef,undef,undef,undef,undef,undef,undef,$fs_size,undef,undef,undef,undef,undef) = - stat( $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'. - getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'})); - $row->{'fs_size'} = $fs_size; + $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) ); + #$row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) ); + + my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize"; + if ($row->{size} > $max_archive_size) { + ($row->{volumes}, $row->{inc_size_calc}) = getVolumes($row->{id}); + } + + $row->{size} = sprintf("%0.2f", $row->{size} / 1024 / 1024); + + # do some cluster calculation (approximate) + $row->{inc_size} = int(($row->{inc_size} + 1023 ) / ( 2 * 1024 ) * 2); + $row->{inc_size_calc} ||= $row->{inc_size}; push @ret, $row; } - return @ret; + return @ret; } -sub displayBackupsGrid() { +sub displayBackupsGrid($) { + + my $param = shift; + + my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize"; + my $max_archive_file_size = $Conf{MaxArchiveFileSize} || die "no MaxFileInSize"; my $retHTML .= q{ -