Changeset 368


Ignore:
Timestamp:
07/26/12 18:18:22 (12 years ago)
Author:
Kris Deugau
Message:

/trunk

First stage implementation of export caching for performance. See #38.
A lot of the actual performance boost comes from indexes on a couple of
columns in WHERE clauses:

  • status column on domains and revzones
  • type, domain_id and rdns_id columns on records

Net speedup on ~100K records and ~3K zones was
~120s -> 20s (no cache) -> 4s (cache active)

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/DNSDB.pm

    r367 r368  
    3030use NetAddr::IP qw(:lower);
    3131use POSIX;
     32use Fcntl qw(:flock);
     33
    3234use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
    3335
     
    142144#               cssdir  => 'templates/',
    143145                sessiondir      => 'session/',
     146                exportcache     => 'cache/',
    144147
    145148                # Session params
     
    12711274      $config{log_failures}     = $1 if /^log_failures\s*=\s*([a-z01]+)/i;
    12721275      $config{perpage}          = $1 if /^perpage\s*=\s*(\d+)/i;
     1276      $config{exportcache}      = $1 if m{^exportcache\s*=\s*([a-z0-9/_.-]+)}i;
    12731277    }
    12741278    close CFG;
     
    42094213  my %recflags;
    42104214
    4211   my $domsth = $dbh->prepare("SELECT domain_id,domain,status FROM domains WHERE status=1");
     4215  my $domsth = $dbh->prepare("SELECT domain_id,domain,status,changed FROM domains WHERE status=1");
    42124216  my $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id ".
    4213         "FROM records WHERE domain_id=? AND NOT type=65283");
     4217        "FROM records WHERE domain_id=? AND type < 65280");     # Just exclude all types relating to rDNS
     4218  my $zonesth = $dbh->prepare("UPDATE domains SET changed=0 WHERE domain_id=?");
    42144219  $domsth->execute();
    4215   while (my ($domid,$dom,$domstat) = $domsth->fetchrow_array) {
    4216     $recsth->execute($domid);
    4217     while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid) = $recsth->fetchrow_array) {
    4218       next if $recflags{$recid};
     4220  while (my ($domid,$dom,$domstat,$changed) = $domsth->fetchrow_array) {
     4221##fixme: need to find a way to block opening symlinked files without introducing a race.
     4222#       O_NOFOLLOW
     4223#              If  pathname  is a symbolic link, then the open fails.  This is a FreeBSD extension, which was
     4224#              added to Linux in version 2.1.126.  Symbolic links in earlier components of the pathname  will
     4225#              still be followed.
     4226# but that doesn't help other platforms.  :/
     4227    sysopen(ZONECACHE, "$config{exportcache}/$dom", O_RDWR|O_CREAT);
     4228    flock(ZONECACHE, LOCK_EX);
     4229    if ($changed || -s "$config{exportcache}/$dom" == 0) {
     4230      $recsth->execute($domid);
     4231      while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid) = $recsth->fetchrow_array) {
     4232        next if $recflags{$recid};
    42194233##fixme:  need to store location in the db, and retrieve it here.
    42204234# temporarily hardcoded to empty so we can include it further down.
    4221       my $loc = '';
     4235        my $loc = '';
    42224236
    42234237##fixme:  record validity timestamp. tinydns supports fiddling with timestamps.
     
    42254239# timestamps are TAI64
    42264240# ~~ 2^62 + time()
    4227       my $stamp = '';
    4228 
    4229       # support tinydns' auto-TTL
    4230       $ttl = '' if $ttl == '0';
    4231 
    4232       _printrec_tiny($datafile,'n',\%recflags,$dom,$host,$type,$val,$dist,$weight,$port,$ttl,$loc,$stamp);
    4233       $recflags{$recid} = 1;
    4234 
    4235     } # while ($recsth)
     4241        my $stamp = '';
     4242
     4243        # support tinydns' auto-TTL
     4244        $ttl = '' if $ttl == '0';
     4245
     4246        _printrec_tiny($datafile, 'n', \%recflags,
     4247                $dom, $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp);
     4248
     4249        _printrec_tiny(*ZONECACHE, 'n', \%recflags,
     4250                $dom, $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp)
     4251                if *ZONECACHE;
     4252        # in case the zone shrunk, get rid of garbage at the end of the file.
     4253        truncate(ZONECACHE, tell(ZONECACHE));
     4254
     4255        $recflags{$recid} = 1;
     4256      } # while ($recsth)
     4257    } else {
     4258      # domain not changed, stream from cache
     4259      print $datafile $_ while <ZONECACHE>;
     4260    }
     4261    close ZONECACHE;
     4262    # mark domain as unmodified
     4263    $zonesth->execute($domid);
    42364264  } # while ($domsth)
    42374265
    4238   my $revsth = $dbh->prepare("SELECT rdns_id,revnet,status FROM revzones WHERE status=1 ".
     4266  my $revsth = $dbh->prepare("SELECT rdns_id,revnet,status,changed FROM revzones WHERE status=1 ".
    42394267        "ORDER BY masklen(revnet) DESC");
    42404268# For reasons unknown, we can't sanely UNION these statements.  Feh.
     
    42564284        "FROM records WHERE rdns_id=? AND not type=6 ".
    42574285        "ORDER BY masklen(CAST(val AS inet)) DESC, CAST(val AS inet)");
     4286  $zonesth = $dbh->prepare("UPDATE revzones SET changed=0 WHERE rdns_id=?");
    42584287  $revsth->execute();
    4259   while (my ($revid,$revzone,$revstat) = $revsth->fetchrow_array) {
    4260     $soasth->execute($revid);
    4261     my (@zsoa) = $soasth->fetchrow_array();
    4262     _printrec_tiny($datafile,'y',\%recflags,$revzone,
     4288  while (my ($revid,$revzone,$revstat,$changed) = $revsth->fetchrow_array) {
     4289##fixme: need to find a way to block opening symlinked files without introducing a race.
     4290#       O_NOFOLLOW
     4291#              If  pathname  is a symbolic link, then the open fails.  This is a FreeBSD extension, which was
     4292#              added to Linux in version 2.1.126.  Symbolic links in earlier components of the pathname  will
     4293#              still be followed.
     4294# but that doesn't help other platforms.  :/
     4295    my $tmpzone = NetAddr::IP->new($revzone);
     4296    sysopen(ZONECACHE, "$config{exportcache}/".$tmpzone->network->addr, O_RDWR|O_CREAT);
     4297    flock(ZONECACHE, LOCK_EX);
     4298    if ($changed || -s "$config{exportcache}/".$tmpzone->network->addr == 0) {
     4299      # need to fetch this separately since the rest of the records all (should) have real IPs in val
     4300      $soasth->execute($revid);
     4301      my (@zsoa) = $soasth->fetchrow_array();
     4302      _printrec_tiny($datafile,'y',\%recflags,$revzone,
    42634303        $zsoa[0],$zsoa[1],$zsoa[2],$zsoa[3],$zsoa[4],$zsoa[5],$zsoa[6],'','');
    42644304
    4265     $recsth->execute($revid);
    4266     while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid) = $recsth->fetchrow_array) {
    4267       next if $recflags{$recid};
     4305      $recsth->execute($revid);
     4306      while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid) = $recsth->fetchrow_array) {
     4307        next if $recflags{$recid};
    42684308##fixme:  need to store location in the db, and retrieve it here.
    42694309# temporarily hardcoded to empty so we can include it further down.
    4270       my $loc = '';
     4310        my $loc = '';
    42714311
    42724312##fixme:  record validity timestamp. tinydns supports fiddling with timestamps.
     
    42744314# timestamps are TAI64
    42754315# ~~ 2^62 + time()
    4276       my $stamp = '';
    4277 
    4278       # support tinydns' auto-TTL
    4279       $ttl = '' if $ttl == '0';
    4280 
    4281       _printrec_tiny($datafile,'y',\%recflags,$revzone,$host,$type,$val,$dist,$weight,$port,$ttl,$loc,$stamp);
    4282       $recflags{$recid} = 1;
    4283 
    4284     } # while ($recsth)
     4316        my $stamp = '';
     4317
     4318        # support tinydns' auto-TTL
     4319        $ttl = '' if $ttl == '0';
     4320
     4321        _printrec_tiny($datafile, 'y', \%recflags, $revzone,
     4322                $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp);
     4323        _printrec_tiny(*ZONECACHE, 'y', \%recflags, $revzone,
     4324                $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp)
     4325                if *ZONECACHE;
     4326        # in case the zone shrunk, get rid of garbage at the end of the file.
     4327        truncate(ZONECACHE, tell(ZONECACHE));
     4328
     4329        $recflags{$recid} = 1;
     4330      } # while ($recsth)
     4331    } else {
     4332      # zone not changed, stream from cache
     4333      print $datafile $_ while <ZONECACHE>;
     4334    }
     4335    close ZONECACHE;
     4336    # mark domain as unmodified
     4337    $zonesth->execute($revid);
    42854338  } # while ($domsth)
    42864339
  • trunk/dns-1.0-1.2.sql

    r366 r368  
    2727ALTER TABLE domains ALTER COLUMN changed SET DEFAULT true;
    2828ALTER TABLE domains ALTER COLUMN changed SET NOT NULL;
     29-- ~2x performance boost iff most zones are fed to output from the cache
     30CREATE INDEX dom_status_index ON domains (status);
    2931
    3032CREATE TABLE revzones (
     
    3840    changed boolean DEFAULT true NOT NULL
    3941);
     42CREATE INDEX rev_status_index ON revzones (status);
    4043
    4144ALTER TABLE log ADD COLUMN rdns_id INTEGER;
     
    4952UPDATE records SET rdns_id=0;
    5053ALTER TABLE records ALTER COLUMN rdns_id SET NOT NULL;
     54-- ~120s -> 75s performance boost on 100K records when always exporting all records
     55CREATE INDEX rec_types_index ON records (type);
     56-- Further ~1/3 performance gain, same dataset
     57CREATE INDEX rec_domain_index ON records (domain_id);
     58CREATE INDEX rec_revzone_index ON records (rdns_id);
    5159
    5260-- May as well drop and recreate;  this is nominally static and loaded from the
Note: See TracChangeset for help on using the changeset viewer.