ahjohnson2 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, perl newb presented with and interesting challenge. For this scenario, I'm working with a list of 3 parent elements that contain 2 child elements apiece. I do not have the luxury of working with a database, so a lot of hand jamming the parents/children will take place.

Asia_primary: Tokyo, Seoul

Europe_primary: London, Moscow

Africa_primary: Cairo, Algiers

Where this gets tricky, is in the event of failover. The children do not failover to the same secondary parents. As an example, Asia will be brought offline:

Asia_primary: Down

Europe_primary: London, Moscow, Tokyo

Africa_primary: Cairo, Algiers, Seoul

For the code, am guessing I would need to create a hash of hashes

%parent = ( "europe" => { "london" => "london", "moscow" => "moscow", }, "asia" => { "tokyo" => "tokyo", "seoul" => "seoul", }, "africa" => { "cario" => "cariro", "algiers" => "algiers", }, );

How to handle a down parent and push the children to the secondary parent? Am guessing an additional hash for each scenario would be required. Would appreciate any assistance.

Replies are listed 'Best First'.
Re: Scripting Failover Scenario
by kennethk (Abbot) on Feb 26, 2014 at 22:16 UTC
    First, it seems like this is a situation for a hash of arrays (see perllol and HASHES OF ARRAYS). So your data might look like:
    my %parent = ( europe => [qw| london moscow |], asia => [qw| tokyo seoul |], africa => [qw| cario algiers |], );
    though a hash of hashes might make sense depending on how you access the data.

    Second, do you care about determinism/repeatability in where a city rolls over to? You could just cycle over keys, and push the cities onto the next taker:

    sub fallover { my ($hash, $failure) = @_; my $list = delete($hash->{$failure}) or return; my @targets = keys %$hash; my $i = 0; while (@$list) { my $city = shift @$list; push @{$hash->{$targets[$i++]}}, $city; $i %= @targets; } }

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Thanks for the feedback. I failed to mention the failover sites are predetermined. So in a scenario, if Europe goes down, london fails to asia, and moscow fails to africa. If asia goes down, london is then isoloated (no further failover available). Tokyo would fail to Africa, and Seoul (slated to failover to europe) would also be isolated.

      The option of having the sites roll to the next available parent can't work.

Re: Scripting Failover Scenario
by kcott (Archbishop) on Feb 27, 2014 at 10:45 UTC

    G'day ahjohnson2,

    The following achieves the results specifed in your OP and in your subsequent update.

    Note the different data structure I've used. The order of continents is important so I've used an array of hashrefs each with a single continent key. The order of cities is also important so the values of those keys are arrayrefs.

    [Also note that you've misspelled "Cairo" two different ways — this will cause errors that may be hard to track down — taking care over such details is important.]

    #!/usr/bin/env perl -l use strict; use warnings; use Data::Dump; my @parent = ( { Europe => [ qw{ London Moscow } ] }, { Asia => [ qw{ Tokyo Seoul } ] }, { Africa => [ qw{ Cairo Algiers } ] }, ); my @current; reset_current(\@parent, \@current); print '*** Starting State ***'; print_current_state(\@current); print '*** Asia Down ***'; failover(Asia => \@current); print_current_state(\@current); print '*** Reset State ***'; reset_current(\@parent, \@current); print_current_state(\@current); print '*** Europe Down ***'; failover(Europe => \@current); print_current_state(\@current); print '*** Asia Down ***'; failover(Asia => \@current); print_current_state(\@current); sub failover { my ($down, $current) = @_; my @cities_to_failover = map { (keys %$_)[0] eq $down ? @{$_->{$down}} : () } @$curre +nt; for (@$current) { my ($continent) = keys %$_; next unless @{$_->{$continent}}; if ($continent eq $down) { @{$_->{$continent}} = (); } else { push @{$_->{$continent}}, shift @cities_to_failover; } } } sub print_current_state { my ($current) = @_; dd $current; } sub reset_current { my ($parent, $current) = @_; @$current = (); for (@$parent) { my ($continent) = keys %$_; push @$current, { $continent => [ @{$_->{$continent}} ] }; } }

    Output:

    *** Starting State *** [ { Europe => ["London", "Moscow"] }, { Asia => ["Tokyo", "Seoul"] }, { Africa => ["Cairo", "Algiers"] }, ] *** Asia Down *** [ { Europe => ["London", "Moscow", "Tokyo"] }, { Asia => [] }, { Africa => ["Cairo", "Algiers", "Seoul"] }, ] *** Reset State *** [ { Europe => ["London", "Moscow"] }, { Asia => ["Tokyo", "Seoul"] }, { Africa => ["Cairo", "Algiers"] }, ] *** Europe Down *** [ { Europe => [] }, { Asia => ["Tokyo", "Seoul", "London"] }, { Africa => ["Cairo", "Algiers", "Moscow"] }, ] *** Asia Down *** [ { Europe => [] }, { Asia => [] }, { Africa => ["Cairo", "Algiers", "Moscow", "Tokyo"] }, ]

    -- Ken