Changeset 716 for trunk/cgi-bin


Ignore:
Timestamp:
05/06/15 14:01:30 (10 years ago)
Author:
Kris Deugau
Message:

/trunk

Add internal utility sub _deleteCascade(), necessary for coming
mergeBlocks() and probably useful for some new cases of deleteBlock().

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cgi-bin/IPDB.pm

    r715 r716  
    208208
    209209} # end _compactFree()
     210
     211
     212## IPDB::_deleteCascade()
     213# Internal sub.  Deletes an allocation and all subcomponents
     214sub _deleteCascade {
     215  my $dbh = shift;
     216  my $id = shift;
     217
     218  my $binfo = getBlockData($dbh, $id);
     219
     220##fixme:  special-case master blocks up here and quickly delete based on master_id,
     221# instead of wasting time tracing parent relations
     222
     223  # grab all allocations in the master within the CIDR of the block to be deleted
     224  my %parents;
     225  my %cidrlist;
     226##fixme: limit by VRF?
     227  my $sth = $dbh->prepare("SELECT cidr,id,parent_id FROM allocations WHERE cidr <<= ? AND master_id = ?");
     228  $sth->execute($binfo->{block}, $binfo->{master_id});
     229  while (my ($cidr, $cid, $pid) = $sth->fetchrow_array) {
     230    $parents{$cid} = $pid;
     231    $cidrlist{$cid} = $cidr;
     232  }
     233
     234  # Trace the parent relations up the tree until we either hit parent ID 0 (we've found a master block
     235  # but not the parent we're looking for - arguably this is already an error) or the parent ID matches
     236  # the passed ID.  If the latter, push the whole set into a second flag hash, so we can terminate
     237  # further tree-tracing early.
     238  my %found;
     239  foreach my $cid (keys %parents) {
     240    my @tmp;
     241    if ($cid == $id) {
     242      # "child" is the ID we've been asked to cascade-delete.
     243      $found{$cid}++;
     244    } elsif ($found{$cid}) {
     245      # ID already seen and the chain terminates in our parent.
     246    } elsif ($parents{$cid} == $id) {
     247      # Immediate parent is the target parent
     248      $found{$cid}++;
     249    } else {
     250      # Immediate parent isn't the one we're looking for.  Walk the chain up until we hit our parent,
     251      # the nonexistent parent id 0, or undefined (ID is not a child of the target ID at all)
     252      # There are probably better ways to structure this loop.
     253      while (1) {
     254        # cache the ID
     255        push @tmp, $cid;
     256        # some very particularly defined loop ending conditions
     257        if (!defined($parents{$cid}) || $parents{$cid} == $id || $parents{$cid} == 0) {
     258          last;
     259        } else {
     260          # if we haven't found either the desired parent or another limiting condition,
     261          # reset the ID to the parent next up the tree
     262          $cid = $parents{$cid};
     263        }
     264      }
     265      # if the current chain of relations ended with our target parent, shuffle the cached IDs into a flag hash
     266      if (defined($parents{$cid}) && $parents{$cid} == $id) {
     267        foreach (@tmp) { $found{$_}++; }
     268      }
     269    } # else
     270  } # foreach my $cid
     271
     272  # Use the keys in the flag hash to determine which allocations to actually delete.
     273  # Delete matching freeblocks and pool IPs;  their parents are going away so we want
     274  # to make sure we don't leave orphaned records lying around loose.
     275  my @dellist = keys %found;
     276  push @dellist, $id;  # Just In Case the target ID didn't make the list earlier.
     277  my $b = '?'. (',?' x $#dellist);
     278  $dbh->do("DELETE FROM allocations WHERE id IN ($b)", undef, (@dellist) );
     279  $dbh->do("DELETE FROM freeblocks WHERE parent_id IN ($b)", undef, (@dellist) );
     280  $dbh->do("DELETE FROM poolips WHERE parent_id IN ($b)", undef, (@dellist) );
     281
     282  # Insert a new free block in the target's parent, unless we just deleted a whole master block.
     283  if ($binfo->{type} ne 'mm') {
     284    my $pinfo = getBlockData($dbh, $binfo->{parent_id});
     285    my $pt = (split //, $pinfo->{type})[1];
     286    $dbh->do("INSERT INTO freeblocks (cidr,city,routed,parent_id,vrf,master_id) VALUES (?,?,?,?,?,?)", undef,
     287        $binfo->{block}, $pinfo->{city}, $pt, $binfo->{parent_id}, $pinfo->{vrf}, $binfo->{master_id});
     288  }
     289
     290##todo: and hey!  bonus!  we can return @dellist, or something (%cidrlist{@dellist})
     291} # end _deleteCascade()
    210292
    211293
Note: See TracChangeset for help on using the changeset viewer.