package Net::Paraget::AssignmentManager;
#
# $Id: AssignmentManager.pm,v 1.7 2001/05/10 04:33:48 lrclause Exp $
#
use strict;
use Carp;
use Net::Paraget::Assignment;
use Net::Paraget::Interval;
use Class::MethodMaker
get_set => [ qw( context
file
min_splittable_eta
) ],
new_hash_init => [ qw( new hash_init ) ];
sub state
{
my ( $self, $string, $priority ) = @_;
main::state( "assignment manager: " . $string, $priority );
}
sub get_n_assignments
{
my ( $self, $n ) = @_;
my $context = $self->context();
my $server_queue = $context->server_queue();
my @assignments = ();
while ( $n > 0 )
{
my ( $server, $interval ) = $self->find_best_match();
last unless defined $server and defined $interval;
my $split_at = $self->find_split_offset( $interval, $server );
$self->state( "Best match " . $server->info()
. " with interval " . $interval->info()
. " starting at $split_at",
3
);
last if $split_at >= $interval->end();
my $to_assign = $interval->split( $split_at );
my $mirror = $server->get_mirror();
$server_queue->remove( $server );
my $assignment =
Net::Paraget::Assignment->new( mirror => $mirror,
interval => $to_assign,
file => $self->file,
server => $server,
);
$self->state( "created assignment " . $assignment->info(), 3 );
$to_assign->hash_init( assignment => $assignment,
completed => 1,
);
push @assignments, $assignment;
$n--;
}
return @assignments;
}
sub find_split_offset
{
my ( $self, $interval, $server ) = @_;
my $prev = $interval->prev();
return 0 unless $prev->assignment();
my $prev_speed = 0;
my $prev_assignment = $prev->assignment();
$prev_speed = $prev_assignment->server->a_speed() if $prev_assignment;
my $time = $server->time_over_interval( $interval );
my $offset = int ( $interval->start() + $time * $prev_speed );
return $offset;
}
sub interval_can_be_split
{
my ( $self, $interval ) = @_;
my $estimation = $interval->eta();
my $min_eta = $self->min_splittable_eta();
return 1 if not defined $estimation;
my $x = $min_eta <= $estimation;
if ( not $x )
{
$self->state( "interval cannot be split: eta of $estimation is less than minimal $min_eta", 3 );
}
return $min_eta <= $estimation;
}
sub pick_untried_server
{
my ($self) = @_;
foreach my $server ( $self->context()->server_queue()->servers() )
{
return $server if not $server->tries() and not $server->disabled();
}
croak "Internal error: No untried servers in pick_untried_server";
}
sub pick_server_to_refresh
{
my ($self) = @_;
my $oldest;
foreach my $server ( $self->context->server_queue()->servers() )
{
$oldest = $server if (not defined $oldest or
not defined $server->last_try() or
(defined $oldest->last_try() and
$server->last_try() < $oldest->last_try()));
}
return $oldest;
}
sub pick_fastest_server
{
my ($self) = @_;
my $best_server;
foreach my $server ( $self->context->server_queue->servers() )
{
$best_server = $server if (not defined $best_server
and defined $server->speed());
if ($server->speed() and
$server->speed() > $best_server->speed()) {
$best_server = $server;
}
}
return $best_server;
}
sub pick_slowest_interval
{
my ($self) = @_;
my $best_interval;
foreach my $interval ( $self->context->interval_manager->uncompleted() )
{
next unless $self->interval_can_be_split($interval);
$best_interval = $interval if not defined $best_interval;
if (not $interval->prev()->assignment()) {
if ($best_interval->assignment()) {
if ($best_interval->size() < $interval->size()) {
$best_interval = $interval;
}
} else {
$best_interval = $interval;
}
} else {
next if not $best_interval->prev()->assignment();
next if not defined $interval->prev()->assignment()->client->estimated_time_to_completion();
next if not defined $best_interval->prev()->assignment()->client->estimated_time_to_completion();
if ($interval->prev()->assignment()->client()->estimated_time_to_completion() >
$best_interval->prev()->assignment()->client()->estimated_time_to_completion()) {
$best_interval = $interval;
}
}
}
return $best_interval;
}
sub pick_server_select_method
{
my ($self) = @_;
my $num_untried = 0;
foreach my $server ( $self->context->server_queue->servers() )
{
$num_untried++ if not $server->disabled() and not $server->tries();
}
if ($num_untried > 0)
{
my $probability = $num_untried / $self->context->server_queue->servers();
if ($probability < 0.25) { $probability = 0.25; }
return "pick_untried_server" if $probability > rand();
}
return "pick_server_to_refresh" if rand() > 0.10;
return "pick_fastest_server";
}
sub find_best_match
{
my ( $self ) = @_;
my $best_server;
my $best_interval;
$best_interval = $self->pick_slowest_interval();
return undef, undef unless defined $best_interval;
my $server_method = $self->pick_server_select_method();
$best_server = $self->$server_method();
return undef, undef if not defined $best_server;
main::state("Found ".$best_server->as_string()." using $server_method", 1);
return $best_server, $best_interval;
}
sub complex_find_best_match
{
my ( $self ) = @_;
my $optimal_time = $self->optimal_time();
return unless defined $optimal_time;
my $best_diff = undef;
my $best_server;
my $best_interval;
foreach my $server ( $self->context->server_queue->servers() )
{
foreach my $interval ( $self->context->interval_manager->uncompleted() )
{
$self->state ("Testing for " . $server->id() . " vs interval " . $interval->info(), 4 );
next unless $self->interval_can_be_split($interval);
my $my_time = $server->time_over_interval( $interval );
$self->state( "est time is $my_time", 4 );
my $diff = abs( $optimal_time - $my_time );
if ( not defined $best_diff or $diff < $best_diff )
{
$best_diff = $diff;
$best_server = $server;
$best_interval = $interval;
}
}
}
return $best_server, $best_interval;
}
sub optimal_time
{
my ( $self ) = @_;
my $total_server_speed = $self->total_server_speed() or return undef;
my $total_uncompleted_size =
$self->context->interval_manager->total_uncompleted_size();
return $total_uncompleted_size / $total_server_speed;
}
sub total_server_speed
{
my ( $self ) = @_;
my $server_list = $self->context->server_list();
my $speed = 0;
foreach my $server ( $self->context->server_queue->servers() )
{
$speed += $server->a_speed() unless $server->disabled();
}
return $speed;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1