mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-31 01:56:39 +00:00
306 lines
9.1 KiB
Perl
306 lines
9.1 KiB
Perl
package xCAT::Scope;
|
|
|
|
use xCAT::Utils;
|
|
use xCAT::Table;
|
|
use xCAT::TableUtils;
|
|
use xCAT::ServiceNodeUtils qw(getSNList);
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 split_node_array
|
|
|
|
Split a node array into multiple subsets in case to handle them in parallel.
|
|
|
|
Arguments:
|
|
Reference of source array
|
|
Maximum subset number
|
|
Default element capacity in each subset
|
|
Returns: An array of all subsets
|
|
Error:
|
|
none
|
|
Example:
|
|
my $subsets = split_node_array(\@nodes, 5, 250);
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub split_node_array {
|
|
my $source = shift;
|
|
if ($source =~ /xCAT::Scope/) {
|
|
$source = shift;
|
|
}
|
|
my $max_sub = shift;
|
|
my $capacity = shift;
|
|
|
|
if ($max_sub < 2) {return [$source];}
|
|
|
|
my @dest = ();
|
|
my $total = $#{$source} + 1;
|
|
my $n_sub = int ($total / $capacity);
|
|
unless ($n_sub * $capacity == $total) { $n_sub++;} #POSIX::ceil
|
|
|
|
if ( $n_sub <= 1 ) {
|
|
# Only 1 subset is enough
|
|
$dest[0] = $source;
|
|
|
|
} elsif ( $n_sub > $max_sub ) {
|
|
# Exceed, then to recaculate the capacity of each subset as we only allow max_sub
|
|
$capacity = int ($total / $max_sub);
|
|
if ( $total % $max_sub > 0 ) {
|
|
$capacity += 1;
|
|
}
|
|
my $start = $end = 0;
|
|
for (1..$max_sub) {
|
|
$end = $start + $capacity - 1;
|
|
if ( $end > $total - 1 ) {
|
|
$end = $total - 1
|
|
}
|
|
|
|
my @temp = @$source[$start..$end];
|
|
$dest[$_-1]=\@temp;
|
|
$start = $end + 1;
|
|
}
|
|
|
|
} else {
|
|
# Only n_sub subsets are required, split the noderange into each subset
|
|
my $start = $end = 0;
|
|
for (1..$n_sub) {
|
|
$end = $start + $capacity - 1;
|
|
if ( $end > $total - 1 ) {
|
|
$end = $total - 1
|
|
}
|
|
#print "subset #$_: $start to $end";
|
|
my @temp = @$source[$start..$end];
|
|
$dest[$_-1]=\@temp;
|
|
$start = $end + 1;
|
|
}
|
|
}
|
|
|
|
return \@dest;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 get_parallel_scope
|
|
|
|
Convert a request object to an array of multiple requests according to the
|
|
splitted node range.
|
|
|
|
Arguments:
|
|
Reference of request
|
|
Maximum subset number: Optional, default is 5
|
|
Default element capacity in each subset: Optional, default is 250
|
|
Returns: An array of requests
|
|
Error:
|
|
none
|
|
Example:
|
|
my $reqs = xCAT::Scope->get_parallel_scope($request);
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub get_parallel_scope {
|
|
my $req = shift;
|
|
if ($req =~ /xCAT::Scope/) {
|
|
$req = shift;
|
|
}
|
|
my ($max_sub, $capacity) = @_;
|
|
#TODO, make the value configurable
|
|
unless ($max_sub) { $max_sub = 5; }
|
|
unless ($capacity) { $capacity = 250; }
|
|
|
|
my $subsets = split_node_array(\@{$req->{node}}, $max_sub, $capacity);
|
|
# Just return the origin one if node range is not big enough.
|
|
if ($#{$subsets} < 1) { return [$req]; }
|
|
|
|
my @requests = ();
|
|
foreach (@$subsets) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{node} = $_;
|
|
push @requests, $reqcopy;
|
|
}
|
|
return \@requests;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 get_broadcast_scope_with_parallel
|
|
|
|
Convert a request object to an array of multiple requests according to the
|
|
splitted node range. Also it replicates the requests to all required service
|
|
nodes or management node.
|
|
|
|
Arguments:
|
|
Reference of request
|
|
SN list: Array of target service nodes
|
|
Returns: An array of requests
|
|
Error:
|
|
none
|
|
Example:
|
|
my $reqs = xCAT::Scope->get_broadcast_scope_with_parallel($request, \@snlist);
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub get_broadcast_scope_with_parallel {
|
|
my $req = shift;
|
|
if ($req =~ /xCAT::Scope/) {
|
|
$req = shift;
|
|
}
|
|
#Exit if the packet has been preprocessed in its history
|
|
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
|
|
$req->{_xcatpreprocessed}->[0] = 1;
|
|
|
|
my $snlist = shift;
|
|
|
|
my $reqs = get_parallel_scope($req);
|
|
|
|
my @requests = (); # The request array will be return.
|
|
push @requests, @$reqs;
|
|
|
|
# when this method is called on service node, it is required to broadcast to MN too.
|
|
# get site.master from DB in order to dispatch to MN ( MN will not be added in servicenode table)
|
|
if ( xCAT::Utils->isServiceNode() ) {
|
|
my @entries = xCAT::TableUtils->get_site_attribute("master");
|
|
my $master = $entries[0];
|
|
foreach (@$reqs) {
|
|
my $reqcopy = {%$_};
|
|
$reqcopy->{'_xcatdest'} = $master;
|
|
push @requests, $reqcopy;
|
|
}
|
|
}
|
|
|
|
#Broadcast the request to all service nodes
|
|
foreach (@$snlist) {
|
|
my $xcatdest = $_;
|
|
next unless (xCAT::NetworkUtils->thishostisnot($xcatdest));
|
|
|
|
foreach (@$reqs) {
|
|
my $reqcopy = {%$_};
|
|
$reqcopy->{'_xcatdest'} = $xcatdest;
|
|
push @requests, $reqcopy;
|
|
}
|
|
}
|
|
return \@requests;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 get_broadcast_disjoint_scope_with_parallel
|
|
|
|
Convert a request object to an array of multiple requests according to the
|
|
splitted node range. Also it replicates the requests to all required service
|
|
nodes or management node, but the request to a service node will only contains
|
|
the node range it manages.
|
|
|
|
Arguments:
|
|
Reference of request
|
|
SN hash: Hash of target service nodes => Managed CNs
|
|
Special servers: Array of servers, those servers are required to handle whole noderange.
|
|
Returns: An array of requests
|
|
Error:
|
|
none
|
|
Example:
|
|
my $reqs = xCAT::Scope->get_broadcast_disjoint_scope_with_parallel($request, \@snhash);
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub get_broadcast_disjoint_scope_with_parallel {
|
|
my $req = shift;
|
|
if ($req =~ /xCAT::Scope/) {
|
|
$req = shift;
|
|
}
|
|
#Exit if the packet has been preprocessed in its history
|
|
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
|
|
$req->{_xcatpreprocessed}->[0] = 1;
|
|
|
|
my $sn_hash = shift;
|
|
my $extras = shift;
|
|
|
|
my @requests = (); # The request array will be return.
|
|
my $reqs = get_parallel_scope($req);
|
|
|
|
my $handled4me = 0; # indicate myself is already handled.
|
|
if (xCAT::Utils->isMN()) { # For MN, add itself always.
|
|
push @requests, @$reqs;
|
|
$handled4me = 1;
|
|
}
|
|
my %prehandledhash = ();# the servers which is already handled.
|
|
foreach (@$extras) {
|
|
my $xcatdest = $_;
|
|
if (xCAT::NetworkUtils->thishostisnot($xcatdest)) {
|
|
# TODO, To avoid sending request to a multi-home server many times.
|
|
foreach (@$reqs) {
|
|
my $reqcopy = {%$_};
|
|
$reqcopy->{'_xcatdest'} = $xcatdest;
|
|
push @requests, $reqcopy;
|
|
}
|
|
$prehandledhash{$xcatdest} = 1;
|
|
} elsif ($handled4me == 0) {
|
|
push @requests, @$reqs;
|
|
$handled4me = 1;
|
|
}
|
|
}
|
|
|
|
#Broadcast the request to all available service nodes
|
|
foreach (keys %$sn_hash) {
|
|
my $xcatdest = $_;
|
|
# to check if the SN already handled
|
|
next if (exists($prehandledhash{$xcatdest}));
|
|
|
|
if (xCAT::NetworkUtils->thishostisnot($xcatdest)) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{'_xcatdest'} = $xcatdest;
|
|
$reqcopy->{'node'} = $sn_hash->{$xcatdest};
|
|
|
|
$reqs = get_parallel_scope($reqcopy);
|
|
push @requests, @$reqs;
|
|
} elsif ($handled4me == 0) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{'node'} = $sn_hash->{$xcatdest};
|
|
|
|
$reqs = get_parallel_scope($reqcopy);
|
|
push @requests, @$reqs;
|
|
$handled4me = 1;
|
|
}
|
|
}
|
|
|
|
return \@requests;
|
|
}
|
|
|
|
|
|
sub get_broadcast_scope {
|
|
my $req = shift;
|
|
if ($req =~ /xCAT::Scope/) {
|
|
$req = shift;
|
|
}
|
|
$callback = shift;
|
|
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
|
|
|
|
#Exit if the packet has been preprocessed in its history
|
|
my @requests = ({%$req}); #Start with a straight copy to reflect local instance
|
|
foreach (xCAT::ServiceNodeUtils->getSNList()) {
|
|
if (xCAT::NetworkUtils->thishostisnot($_)) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{'_xcatdest'} = $_;
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
push @requests, $reqcopy;
|
|
}
|
|
}
|
|
return \@requests;
|
|
|
|
#my $sitetab = xCAT::Table->new('site');
|
|
#(my $ent) = $sitetab->getAttribs({key=>'xcatservers'},'value');
|
|
#$sitetab->close;
|
|
#if ($ent and $ent->{value}) {
|
|
# foreach (split /,/,$ent->{value}) {
|
|
# if (xCAT::NetworkUtils->thishostisnot($_)) {
|
|
# my $reqcopy = {%$req};
|
|
# $reqcopy->{'_xcatdest'} = $_;
|
|
# push @requests,$reqcopy;
|
|
# }
|
|
# }
|
|
#}
|
|
#return \@requests;
|
|
}
|
|
|
|
1;
|