Even more accurate size estimation; reduce how much we need to run mkisofs

This commit is contained in:
Steve McIntyre 2006-12-11 17:52:25 +00:00
parent 8b318a9693
commit ad1906c27b
3 changed files with 338 additions and 266 deletions

View File

@ -18,307 +18,372 @@ my $log_opened = 0;
my $old_split = $/;
sub msg_ap {
my $level = shift;
if (!$log_opened) {
open(AP_LOG, ">> $tdir/$codename/log.add_packages")
|| die "Can't write in $tdir/log.add_packages!\n";
}
print AP_LOG @_;
my $level = shift;
if (!$log_opened) {
open(AP_LOG, ">> $tdir/$codename/log.add_packages")
|| die "Can't write in $tdir/log.add_packages!\n";
}
print AP_LOG @_;
}
sub size_in_blocks {
my $size_in_bytes = shift;
return (1 + int(($size_in_bytes + $iso_blksize - 1) / $iso_blksize));
}
# From a package name and section, work out the directory where its
# corresponding Packages file should live
sub Packages_dir {
my $dir = shift;
my $file = shift;
my $section = shift;
my $dir = shift;
my $file = shift;
my $section = shift;
my ($pdir, $dist);
my ($pdir, $dist);
if ($file =~ /\/main\//) {
$dist = "main";
} elsif ($file =~ /\/contrib\//) {
$dist = "contrib";
} elsif ($file =~ /\/non-free\//) {
$dist = "non-free";
} elsif ($file =~ /\/local\//) {
$dist = "local";
}
if ($file =~ /\/main\//) {
$dist = "main";
} elsif ($file =~ /\/contrib\//) {
$dist = "contrib";
} elsif ($file =~ /\/non-free\//) {
$dist = "non-free";
} elsif ($file =~ /\/local\//) {
$dist = "local";
}
$pdir = "$dir/dists/$codename/$dist";
if ($section eq "debian-installer") {
$pdir = "$dir/dists/$codename/$dist/debian-installer";
}
return $pdir;
$pdir = "$dir/dists/$codename/$dist";
if ($section eq "debian-installer") {
$pdir = "$dir/dists/$codename/$dist/debian-installer";
}
return $pdir;
}
# Dump the apt-cached data into a Packages file; make the parent dir
# for the Packages file if necesssary
sub add_Packages_entry {
my ($p, $file, $section, $pdir, $pkgfile, $gz);
my $dir = shift;
my $arch = shift;
my ($st1, $st2, $size1, $size2);
my ($p, $file, $section, $pdir, $pkgfile, $gz);
my $dir = shift;
my $arch = shift;
my ($st1, $st2, $size1, $size2);
my $blocks_added = 0;
my $old_blocks = 0;
my $new_blocks = 0;
m/^Package: (\S+)/m and $p = $1;
m/^Section: (\S+)/m and $section = $1;
m/^Package: (\S+)/m and $p = $1;
m/^Section: (\S+)/m and $section = $1;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/source";
$pkgfile = "$pdir/Sources";
} else {
m/^Filename: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/binary-$arch";
$pkgfile = "$pdir/Packages";
}
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/source";
$pkgfile = "$pdir/Sources";
} else {
m/^Filename: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/binary-$arch";
$pkgfile = "$pdir/Packages";
}
msg_ap(0, " Adding $p to $pkgfile(.gz)\n");
if (! -d $pdir) {
system("mkdir -p $pdir");
}
open(PFILE, ">>$pkgfile");
print PFILE $_;
close(PFILE);
msg_ap(0, " Adding $p to $pkgfile(.gz)\n");
if (! -d $pdir) {
system("mkdir -p $pdir");
$blocks_added++;
}
$gz = gzopen("$pkgfile.gz", "ab9") or die "Failed to open $pkgfile.gz: $gzerrno\n";
$gz->gzwrite($_) or die "Failed to write $pkgfile.gz: $gzerrno\n";
$gz->gzclose();
if (-e $pkgfile) {
$st1 = stat("$pkgfile");
$st2 = stat("$pkgfile.gz");
$size1 = $st1->size;
$size2 = $st2->size;
msg_ap(0, " now $size1 / $size2 bytes\n");
$old_blocks = size_in_blocks($st1->size);
}
if (-e "$pkgfile.gz") {
$st1 = stat("$pkgfile.gz");
$old_blocks += size_in_blocks($st1->size);
}
open(PFILE, ">>$pkgfile");
print PFILE $_;
close(PFILE);
$gz = gzopen("$pkgfile.gz", "ab9") or die "Failed to open $pkgfile.gz: $gzerrno\n";
$gz->gzwrite($_) or die "Failed to write $pkgfile.gz: $gzerrno\n";
$gz->gzclose();
$st1 = stat("$pkgfile");
$st2 = stat("$pkgfile.gz");
$size1 = $st1->size;
$size2 = $st2->size;
$new_blocks += size_in_blocks($st1->size);
$new_blocks += size_in_blocks($st2->size);
$blocks_added += ($new_blocks - $old_blocks);
msg_ap(0, " now $size1 / $size2 bytes, $blocks_added blocks added\n");
return $blocks_added;
}
sub add_md5_entry {
my $dir = shift;
my $arch = shift;
my ($pdir, $file, $md5);
my $md5file = "$dir/md5sum.txt";
my ($st, $size);
my $p;
my $dir = shift;
my $arch = shift;
my ($pdir, $file, $md5);
my $md5file = "$dir/md5sum.txt";
my ($st, $size);
my $p;
my $blocks_added = 0;
my $old_blocks = 0;
my $new_blocks = 0;
m/^Package: (\S+)/mi and $p = $1;
open(MD5FILE, ">>$md5file");
m/^Package: (\S+)/mi and $p = $1;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $pdir = $1;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and print MD5FILE "$1 ./$pdir/$3\n";
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and print MD5FILE "$1 ./$pdir/$3\n";
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and print MD5FILE "$1 ./$pdir/$3\n";
} else {
m/^Filename: (\S+)/m and $file = $1;
m/^MD5sum: (\S+)/m and print MD5FILE "$1 ./$file\n";
}
if (-e $md5file) {
$st = stat("$md5file");
$old_blocks = size_in_blocks($st->size);
}
close(MD5FILE);
msg_ap(0, " Adding $p to md5sum.txt\n");
$st = stat("$dir/md5sum.txt");
$size = $st->size;
msg_ap(0, " now $size bytes\n");
open(MD5FILE, ">>$md5file");
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $pdir = $1;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and print MD5FILE "$1 ./$pdir/$3\n";
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and print MD5FILE "$1 ./$pdir/$3\n";
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and print MD5FILE "$1 ./$pdir/$3\n";
} else {
m/^Filename: (\S+)/m and $file = $1;
m/^MD5sum: (\S+)/m and print MD5FILE "$1 ./$file\n";
}
close(MD5FILE);
msg_ap(0, " Adding $p to $md5file\n");
$st = stat("$md5file");
$size = $st->size;
$new_blocks = size_in_blocks($st->size);
$blocks_added = $new_blocks - $old_blocks;
msg_ap(0, " now $size bytes, added $blocks_added blocks\n");
return $blocks_added;
}
# Roll back the results of add_Packages_entry()
sub remove_Packages_entry {
my ($p, $file, $section, $pdir, $pkgfile, $tmp_pkgfile, $match, $gz);
my $dir = shift;
my $arch = shift;
my ($st1, $st2, $size1, $size2);
my ($p, $file, $section, $pdir, $pkgfile, $tmp_pkgfile, $match, $gz);
my $dir = shift;
my $arch = shift;
my ($st1, $st2, $size1, $size2);
my $blocks_removed = 0;
my $old_blocks = 0;
my $new_blocks = 0;
m/^Package: (\S+)/m and $p = $1;
m/^Section: (\S+)/m and $section = $1;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/source";
$pkgfile = "$pdir/Sources";
} else {
m/^Filename: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/binary-$arch";
$pkgfile = "$pdir/Packages";
}
if (-e $pkgfile) {
$st1 = stat("$pkgfile");
$old_blocks += size_in_blocks($st1->size);
}
if (-e "$pkgfile.gz") {
$st2 = stat("$pkgfile.gz");
$old_blocks += size_in_blocks($st2->size);
}
$tmp_pkgfile = "$pkgfile" . ".rollback";
msg_ap(0, " Removing $p from $pkgfile(.gz)\n");
open(IFILE, "<$pkgfile");
open(OFILE, ">>$tmp_pkgfile");
$gz = gzopen("$pkgfile.gz", "wb9");
while (defined($match = <IFILE>)) {
if (! ($match =~ /^Package: \Q$p\E$/m)) {
print OFILE $match;
$gz->gzwrite($match) or die "Failed to write $pkgfile.gz: $gzerrno\n";
}
}
$gz->gzclose();
close(IFILE);
close(OFILE);
rename $tmp_pkgfile, $pkgfile;
$st1 = stat("$pkgfile");
$st2 = stat("$pkgfile.gz");
$size1 = $st1->size;
$size2 = $st2->size;
$new_blocks += size_in_blocks($st1->size);
$new_blocks += size_in_blocks($st2->size);
$blocks_removed += ($old_blocks - $new_blocks);
msg_ap(0, " now $size1 / $size2 bytes, $blocks_removed blocks removed\n");
return $blocks_removed;
}
sub remove_md5_entry {
my $dir = shift;
my $arch = shift;
my ($pdir, $file, $md5, $match, $present);
my $md5file = "$dir/md5sum.txt";
my $tmp_md5file = "$dir/md5sum.txt.tmp";
my @fileslist;
my ($st, $size, $p);
my $blocks_removed = 0;
my $old_blocks = 0;
my $new_blocks = 0;
$/ = $old_split; # Browse by line again
m/^Package: (\S+)/mi and $p = $1;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $pdir = $1;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and push(@fileslist, "$1 ./$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and push(@fileslist, "$1 ./$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and push(@fileslist, "$1 ./$pdir/$3");
} else {
m/^Filename: (\S+)/m and $file = $1;
m/^MD5Sum: (\S+)/mi and push(@fileslist, "$1 ./$file");
}
if (-e $md5file) {
$st = stat("$md5file");
$old_blocks = size_in_blocks($st->size);
}
open(IFILE, "<$md5file");
open(OFILE, ">>$tmp_md5file");
while (defined($match = <IFILE>)) {
$present = 0;
foreach my $entry (@fileslist) {
if (($match =~ /\Q$entry\E$/m)) {
$present++;
}
}
if (!$present) {
print OFILE $match;
}
}
close(IFILE);
close(OFILE);
$/ = ''; # Browse by paragraph again
rename $tmp_md5file, $md5file;
msg_ap(0, " Removing $p from md5sum.txt\n");
$st = stat("$dir/md5sum.txt");
$size = $st->size;
$new_blocks = size_in_blocks($st->size);
$blocks_removed = $old_blocks - $new_blocks;
msg_ap(0, " now $size bytes, $blocks_removed blocks removed\n");
return $blocks_removed;
}
sub get_file_blocks {
my $realfile = shift;
my $st;
$st = stat($realfile);
return size_in_blocks($st->size);
}
sub add_packages {
my ($p, @files, $d, $realfile, $source, $section, $name, $pkgfile, $pdir);
my ($pkgname, $arch, $dir, $pkg);
my $total_blocks = 0;
my $rollback = 0;
my $option = shift;
if ($option =~ /--rollback/) {
$rollback = 1;
$dir = shift;
} else {
$dir = $option;
}
if (! -d $dir) {
die "add_packages: $dir is not a directory ...";
}
$pkg = shift;
$pkgname = $pkg;
$pkgname =~ s/^.*://;
$arch = $pkg;
$arch =~ s/:.*$//g;
msg_ap(0, "Looking at $pkg: arch $arch, package $pkgname, rollback $rollback\n");
$/ = ''; # Browse by paragraph
$ENV{'ARCH'} = $arch;
if ($arch eq "source") {
open (LIST, "$basedir/tools/apt-selection cache showsrc $pkgname |")
|| die "Can't fork : $!\n";
} else {
open (LIST, "$basedir/tools/apt-selection cache show $pkgname |")
|| die "Can't fork : $!\n";
}
while (defined($_ = <LIST>)) {
undef @files;
m/^Package: (\S+)/m and $p = $1;
m/^Section: (\S+)/m and $section = $1;
$source = $mirror;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/source";
$pkgfile = "$pdir/Sources";
m/^Directory: (\S+)/m and $pdir = $1;
$source=$localdebs if $pdir=~m:local/:;
$source=$security if $pdir=~m:updates/:;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and push(@files, "$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and push(@files, "$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and push(@files, "$pdir/$3");
} else {
m/^Filename: (\S+)/mi and $file = $1;
$pdir = Packages_dir($dir, $file, $section) . "/binary-$arch";
$pkgfile = "$pdir/Packages";
m/^Filename: (\S+)/mi and push(@files, $1);
$source=$localdebs if $1=~m:local/:;
$source=$security if $1=~m:updates/:;
}
$tmp_pkgfile = "$pkgfile" . ".rollback";
if ($rollback) {
# Remove the Packages entry/entries for the specified package
$total_blocks -= remove_Packages_entry($dir, $arch, $_);
$total_blocks -= remove_md5_entry($dir, $arch, $_);
msg_ap(0, " Removing $p from $pkgfile(.gz)\n");
foreach my $file (@files) {
# Count how big the file is we're removing, for checking if the disc is full
$realfile = real_file ("$source/$file");
$total_blocks -= get_file_blocks($realfile);
open(IFILE, "<$pkgfile");
open(OFILE, ">>$tmp_pkgfile");
$gz = gzopen("$pkgfile.gz", "wb9");
while (defined($match = <IFILE>)) {
if (! ($match =~ /^Package: \Q$p\E$/m)) {
print OFILE $match;
$gz->gzwrite($match) or die "Failed to write $pkgfile.gz: $gzerrno\n";
}
}
$gz->gzclose();
close(IFILE);
close(OFILE);
rename $tmp_pkgfile, $pkgfile;
$st1 = stat("$pkgfile");
$st2 = stat("$pkgfile.gz");
$size1 = $st1->size;
$size2 = $st2->size;
msg_ap(0, " now $size1 / $size2 bytes\n");
}
sub remove_md5_entry {
my $dir = shift;
my $arch = shift;
my ($pdir, $file, $md5, $match, $present);
my $md5file = "$dir/md5sum.txt";
my $tmp_md5file = "$dir/md5sum.txt.tmp";
my @fileslist;
my ($st, $size, $p);
$/ = $old_split; # Browse by line again
m/^Package: (\S+)/mi and $p = $1;
if ($arch eq "source") {
m/^Directory: (\S+)/mi and $pdir = $1;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and push(@fileslist, "$1 ./$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and push(@fileslist, "$1 ./$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and push(@fileslist, "$1 ./$pdir/$3");
# Remove the link
unlink ("$dir/$file") or die "Failed to remove $dir/$file\n";
msg_ap(0, " Rollback: removing $dir/$file\n");
}
} else {
m/^Filename: (\S+)/m and $file = $1;
m/^MD5Sum: (\S+)/mi and push(@fileslist, "$1 ./$file");
}
$total_blocks += add_Packages_entry($dir, $arch, $_);
$total_blocks += add_md5_entry($dir, $arch, $_);
open(IFILE, "<$md5file");
open(OFILE, ">>$tmp_md5file");
while (defined($match = <IFILE>)) {
$present = 0;
foreach my $entry (@fileslist) {
if (($match =~ /\Q$entry\E$/m)) {
$present++;
}
}
if (!$present) {
print OFILE $match;
}
}
close(IFILE);
close(OFILE);
foreach my $file (@files) {
# And put the file in the CD tree (with a (hard) link)
$realfile = real_file ("$source/$file");
$/ = ''; # Browse by paragraph again
rename $tmp_md5file, $md5file;
msg_ap(0, " Removing $p from md5sum.txt\n");
$st = stat("$dir/md5sum.txt");
$size = $st->size;
msg_ap(0, " now $size bytes\n");
}
sub get_file_size {
my $realfile = shift;
my $st;
$st = stat($realfile);
return (1 + int(($st->size + $iso_blksize - 1) / $iso_blksize));
}
sub add_packages {
my ($p, @files, $d, $realfile, $source, $section, $name, $pkgfile, $pdir);
my ($pkgname, $arch, $dir, $pkg);
my $total_size = 0;
my $rollback = 0;
my $option = shift;
if ($option =~ /--rollback/) {
$rollback = 1;
$dir = shift;
} else {
$dir = $option;
}
if (! -d $dir) {
die "add_packages: $dir is not a directory ...";
}
$pkg = shift;
$pkgname = $pkg;
$pkgname =~ s/^.*://;
$arch = $pkg;
$arch =~ s/:.*$//g;
msg_ap(0, "Looking at $pkg: arch $arch, package $pkgname, rollback $rollback\n");
$/ = ''; # Browse by paragraph
$ENV{'ARCH'} = $arch;
if ($arch eq "source") {
open (LIST, "$basedir/tools/apt-selection cache showsrc $pkgname |")
|| die "Can't fork : $!\n";
} else {
open (LIST, "$basedir/tools/apt-selection cache show $pkgname |")
|| die "Can't fork : $!\n";
}
while (defined($_ = <LIST>)) {
undef @files;
m/^Package: (\S+)/m and $p = $1;
m/^Section: (\S+)/m and $section = $1;
$source = $mirror;
if ($arch eq "source") {
m/^Directory: (\S+)/m and $pdir = $1;
$source=$localdebs if $pdir=~m:local/:;
$source=$security if $pdir=~m:updates/:;
m/^ (\S+) (\S+) ((\S+).*dsc)/m and push(@files, "$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*diff.gz)/m and push(@files, "$pdir/$3");
m/^ (\S+) (\S+) ((\S+).*tar.gz)/m and push(@files, "$pdir/$3");
if (! -e "$dir/$file") {
# Count how big the file is, for checking if the disc
# is full. ONLY do this if the file is not already
# linked in - consider binary-all packages on a
# multi-arch disc
$total_blocks += get_file_blocks($realfile);
$total_blocks += good_link ($realfile, "$dir/$file");
msg_ap(0, " Linked $dir/$file\n");
} else {
m/^Filename: (\S+)/mi and push(@files, $1);
$source=$localdebs if $1=~m:local/:;
$source=$security if $1=~m:updates/:;
}
if ($rollback) {
# Remove the Packages entry/entries for the specified package
remove_Packages_entry($dir, $arch, $_);
remove_md5_entry($dir, $arch, $_);
foreach my $file (@files) {
# Count how big the file is we're removing, for checking if the disc is full
$realfile = real_file ("$source/$file");
$total_size -= get_file_size($realfile);
# Remove the link
unlink ("$dir/$file") or die "Failed to remove $dir/$file\n";
msg_ap(0, " Rollback: removing $dir/$file\n");
}
} else {
add_Packages_entry($dir, $arch, $_);
add_md5_entry($dir, $arch, $_);
foreach my $file (@files) {
# And put the file in the CD tree (with a (hard) link)
$realfile = real_file ("$source/$file");
if (! -e "$dir/$file") {
# Count how big the file is, for checking if the disc
# is full. ONLY do this if the file is not already
# linked in - consider binary-all packages on a
# multi-arch disc
$total_size += get_file_size($realfile);
good_link ($realfile, "$dir/$file");
msg_ap(0, " Linked $dir/$file\n");
} else {
msg_ap(0, " $dir/$file already linked in\n");
}
}
msg_ap(0, " $dir/$file already linked in\n");
}
}
}
close LIST or die "Something went wrong with apt-cache : $@ ($!)\n";
msg_ap(0, " size $total_size\n");
$/ = $old_split; # Return to line-orientation
return $total_size;
}
close LIST or die "Something went wrong with apt-cache : $@ ($!)\n";
msg_ap(0, " size $total_blocks\n");
$/ = $old_split; # Return to line-orientation
return $total_blocks;
}

View File

@ -8,6 +8,7 @@ my $link_copy = $ENV{'COPYLINK'} || 0;
sub good_link ($$) {
my ($src, $dest) = @_;
my $dir_added = 0;
if (! -e $dest) {
@ -21,6 +22,7 @@ sub good_link ($$) {
if (! -d $ddir) # Create it if not
{
system("mkdir -p $ddir");
$dir_added++;
}
# Link the files
if ($symlink_farm) {
@ -42,6 +44,7 @@ sub good_link ($$) {
}
}
}
return $dir_added;
}
sub real_file ($) {

View File

@ -85,11 +85,13 @@ my $size_swap_check;
# How full should we let the disc get before we stop estimating and
# start running mkisofs?
# Cope with HFS-hybrid disks using extra space for the HFS metadata
if ($archlist =~ /m68k/ || $archlist =~ /powerpc/) {
$size_swap_check = int($maxdiskblocks * 95 / 100);
} else {
$size_swap_check = int($maxdiskblocks * 98 / 100);
}
$size_swap_check = $maxdiskblocks - (40 * $MB / $blocksize);
# And count how many packages added since the last size check was done
# - the estimation code is getting very accurate, so let's reduce the
# number of times we fork mkisofs
my $count_since_last_check = 0;
my $size_check_period = 10;
my $pkgs_this_cd = 0;
my $pkgs_done = 0;
@ -333,10 +335,11 @@ while (defined (my $pkg = <INLIST>)) {
$guess_size = add_packages($cddir, $pkg);
$size += $guess_size;
print LOG "CD $disknum: GUESS_TOTAL is $size after adding $pkg\n";
if ($size > $size_swap_check) {
$size = `$size_check $cddir`;
chomp $size;
print LOG "CD $disknum: Real current size is $size blocks after adding $pkg\n";
if (($size > $size_swap_check) && ($count_since_last_check > $size_check_period)) {
$count_since_last_check = 0;
$size = `$size_check $cddir`;
chomp $size;
print LOG "CD $disknum: Real current size is $size blocks after adding $pkg\n";
}
if ($size > $maxdiskblocks) {
print LOG "CD $disknum over-full ($size > $maxdiskblocks). Rollback!\n";
@ -356,6 +359,7 @@ while (defined (my $pkg = <INLIST>)) {
} else {
$pkgs_this_cd++;
$pkgs_done++;
$count_since_last_check++;
}
}
close(INLIST);