openbsd-ports/infrastructure/lib/DPB/Affinity.pm
espie 45b128b893 fix elusive "jobs don't show up where they should".
duh. put "live" affinity markers while we're building stuff.
We don't re-read the on-disk markers outside of restart (should we ?)
so they HAVE to be in the pkgpath struct proper.
2012-12-30 14:04:17 +00:00

123 lines
3.1 KiB
Perl

# ex:ts=8 sw=4:
# $OpenBSD: Affinity.pm,v 1.4 2012/12/30 14:04:17 espie Exp $
#
# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use strict;
use warnings;
# on multiple hosts setup, it's useful to record which host is building what,
# so that on restart, we try to avoid starting a task on the "wrong" box...
# note that this is only superficially similar to locks
package DPB::Affinity;
use File::Path;
use DPB::PkgPath;
sub new
{
my ($class, $state, $dir) = @_;
File::Path::make_path($dir);
my $o = bless {dir => $dir}, $class;
$o->retrieve_existing_markers($state->logger);
return $o;
}
# each path being built creates an affinity marker
sub affinity_marker
{
my ($self, $v) = @_;
my $s = $v->fullpkgpath;
$s =~ tr|/|.|;
return join('/', $self->{dir}, $s);
}
# we create a separate marker for each path being built in a MULTI_PACKAGES
# setting, so that if we finish building one, we lose the affinity for it.
sub start
{
my ($self, $v, $core) = @_;
my $host = $core->hostname;
for my $w ($v->build_path_list) {
open(my $fh, '>', $self->affinity_marker($w)) or next;
$w->{affinity} = $host;
print $fh "host=$host\n";
print $fh "path=", $w->fullpkgpath, "\n";
close $fh;
}
}
# when we see a package is already done, we have no way of knowing which
# MULTI_PACKAGES led to that, so we just unmark a single file
sub unmark
{
my ($self, $v) = @_;
unlink($self->affinity_marker($v));
delete $v->{affinity};
}
# on the other hand, when we finish building a port, we can unmark all paths.
sub finished
{
my ($self, $v) = @_;
for my $w ($v->build_path_list) {
$self->unmark($w);
}
}
sub retrieve_existing_markers
{
my ($self, $logger) = @_;
my $log = $logger->open('affinity');
opendir(my $d, $self->{dir}) or return;
while (my $e = readdir $d) {
next unless -f "$self->{dir}/$e";
open my $fh, '<', "$self->{dir}/$e" or return;
my ($hostname, $pkgpath);
while (<$fh>) {
chomp;
if (m/^host\=(.*)/) {
$hostname = $1;
}
if (m/^path\=(.*)/) {
$pkgpath = $1;
}
}
close $fh;
next unless (defined $pkgpath) && (defined $hostname);
my $v = DPB::PkgPath->new($pkgpath);
$v->{affinity} = $hostname;
print $log "$$:", $v->fullpkgpath, " => ", $hostname, "\n";
}
close $log;
}
sub simplifies_to
{
my ($self, $v, $w) = @_;
if (defined $v->{affinity}) {
$w->{affinity} //= $v->{affinity};
}
if (defined $w->{affinity}) {
$v->{affinity} //= $w->{affinity};
}
}
1;