tools/page-loader/dump.pl

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/page-loader/dump.pl	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,269 @@
     1.4 +#!/usr/bin/perl
     1.5 +# 
     1.6 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.7 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 +use DBI;    
    1.10 +use CGI::Carp qw(fatalsToBrowser);
    1.11 +use CGI::Request;
    1.12 +use URLTimingDataSet;
    1.13 +use File::Copy ();
    1.14 +use strict;
    1.15 +
    1.16 +use vars qw($dbh $arc $dbroot); # current db, and db/archive
    1.17 +
    1.18 +use constant STALE_AGE => 5 * 60; # seconds
    1.19 +
    1.20 +# show a chart of this run; turned off in automated tests, and where
    1.21 +# an installation hasn't set up the required modules and libraries
    1.22 +use constant SHOW_CHART => 0;
    1.23 +
    1.24 +sub createArchiveMetaTable {
    1.25 +    my $table = "tMetaTable";
    1.26 +    return if -e "$dbroot/archive/$table"; # don't create it if it exists
    1.27 +    warn "createMetaTable:\t$dbroot/archive/$table";
    1.28 +    mkdir "$dbroot/archive" unless -d "$dbroot/archive";
    1.29 +    my ($sth, $sql);
    1.30 +    $sql = qq{
    1.31 +	CREATE TABLE tMetaTable
    1.32 +	    (DATETIME CHAR(14),      LASTPING CHAR(14),
    1.33 +	     ID CHAR(8),             INDEX INTEGER,
    1.34 +	     CUR_IDX INTEGER,        CUR_CYC INTEGER,
    1.35 +	     CUR_CONTENT CHAR(128),  STATE INTEGER,
    1.36 +	     BLESSED INTEGER,        MAXCYC INTEGER,
    1.37 +	     MAXIDX INTEGER,         REPLACE INTEGER,
    1.38 +	     NOCACHE INTEGER,        DELAY INTEGER,
    1.39 +	     REMOTE_USER CHAR(16),   HTTP_USER_AGENT CHAR(128),
    1.40 +	     REMOTE_ADDR CHAR(15),   USER_EMAIL CHAR(32),
    1.41 +	     USER_COMMENT CHAR(256)
    1.42 +	     )
    1.43 +	    };
    1.44 +    $sth = $arc->prepare($sql);
    1.45 +    $sth->execute();
    1.46 +    $sth->finish();
    1.47 +    warn 'created archive meta table';
    1.48 +    return 1;
    1.49 +}
    1.50 +
    1.51 +
    1.52 +sub purgeStaleEntries {
    1.53 +    my $id = shift;
    1.54 +    my $metatable = "tMetaTable";
    1.55 +
    1.56 +    # first, remove dead stuff
    1.57 +    my $sql = qq{SELECT * FROM $metatable 
    1.58 +                   WHERE STATE = "INIT" OR STATE = "OPEN"};
    1.59 +    my $sth = $dbh->prepare($sql);
    1.60 +    $sth->execute();
    1.61 +    my $now = time();
    1.62 +    my $status;
    1.63 +    while (my @data = $sth->fetchrow_array()) {
    1.64 +	my $age = $now - timestamp2Time($data[1]);
    1.65 +	# if OPEN or INIT, and not heard from in 10 minutes, then it's never coming
    1.66 +	# back here again. Delete the entry. Whine in the error_log.
    1.67 +	if ($age > STALE_AGE) {
    1.68 +	    warn "deleting stale record+table, id = $data[2], last = $data[1], @data";
    1.69 +	    $dbh->do( qq(DELETE FROM $metatable WHERE ID = "$data[2]") );
    1.70 +	    $dbh->do("DROP TABLE t" . $data[2]);
    1.71 +	}
    1.72 +	$status .= "$age @data\n";
    1.73 +    }
    1.74 +    $sth->finish();
    1.75 +
    1.76 +    # now move any COMPLETE records to archive
    1.77 +    $sql = qq{SELECT * FROM $metatable};
    1.78 +    $sth = $dbh->prepare($sql);
    1.79 +    $sth->execute();
    1.80 +    $now = time();
    1.81 +    while (my @data = $sth->fetchrow_array()) {
    1.82 +	my $age = $now - timestamp2Time($data[1]);
    1.83 +	# This keeps the "live" entries from growing too slow. 
    1.84 +	# If COMPLETE and older than 10 minutes, move to archive.
    1.85 +	if ($age > STALE_AGE) {
    1.86 +	    warn "moving COMPLETE record+table, id = $data[2], last = $data[1], @data";
    1.87 +	    moveRecordToArchive($data[2], \@data);
    1.88 +	    $dbh->do( qq(DELETE FROM $metatable WHERE ID = "$data[2]") );
    1.89 +	}
    1.90 +    }
    1.91 +    $sth->finish();
    1.92 +
    1.93 +
    1.94 +    if (!SHOW_CHART) {
    1.95 +	# Don't move it if showing a chart. (Otherwise, if showing a 
    1.96 +	# a chart, I'd have to do a little extra work to make sure I 
    1.97 +	# didn't yank the record away from the IMG request)
    1.98 +	$sql = qq{SELECT * FROM $metatable WHERE ID = "$id"};
    1.99 +	$sth = $dbh->prepare($sql);
   1.100 +	$sth->execute();
   1.101 +	while (my @data = $sth->fetchrow_array()) {
   1.102 +	    warn "moving COMPLETE record+table, id = $id, @data\n";
   1.103 +	    moveRecordToArchive($data[2], \@data);
   1.104 +	    $dbh->do( qq(DELETE FROM $metatable WHERE ID = "$data[2]") );
   1.105 +	}
   1.106 +    }
   1.107 +    $sth->finish();
   1.108 +}
   1.109 +
   1.110 +
   1.111 +sub moveRecordToArchive {
   1.112 +    my $id      = shift || die "no id";
   1.113 +    my $dataref = shift || die "no dataref";
   1.114 +    createArchiveMetaTable(); # if it doesn't exist
   1.115 +    insertIntoMetaTable($dataref);
   1.116 +    File::Copy::move("$dbroot/t$id", "$dbroot/archive/t$id");
   1.117 +}
   1.118 +
   1.119 +
   1.120 +sub insertIntoMetaTable {
   1.121 +    my $dataref = shift || die "no dataref";
   1.122 +    my $table = "tMetaTable";
   1.123 +    my ($sth, $sql);
   1.124 +    $sql = qq{
   1.125 +        INSERT INTO $table
   1.126 +             (DATETIME,         LASTPING,     ID,
   1.127 +              INDEX,            CUR_IDX,      CUR_CYC,
   1.128 +              CUR_CONTENT,      STATE,        BLESSED,
   1.129 +              MAXCYC,           MAXIDX,       REPLACE,
   1.130 +              NOCACHE,          DELAY,        REMOTE_USER,
   1.131 +              HTTP_USER_AGENT,  REMOTE_ADDR,  USER_EMAIL,
   1.132 +              USER_COMMENT
   1.133 +              )
   1.134 +          VALUES (?,?,?,?,
   1.135 +                  ?,?,?,?,
   1.136 +                  ?,?,?,?,
   1.137 +                  ?,?,?,?,
   1.138 +                  ?,?,?)
   1.139 +        };
   1.140 +    $sth = $arc->prepare($sql);
   1.141 +    $sth->execute(@$dataref);
   1.142 +    $sth->finish();
   1.143 +}
   1.144 +
   1.145 +
   1.146 +sub timestamp2Time ($) {
   1.147 +    my $str = shift;
   1.148 +    use Time::Local ();
   1.149 +    my @datetime = reverse unpack 'A4A2A2A2A2A2', $str;
   1.150 +    --$datetime[4]; # month: 0-11
   1.151 +    return Time::Local::timelocal(@datetime);
   1.152 +}
   1.153 +
   1.154 +
   1.155 +sub serializeDataSet {
   1.156 +    # package up this data for storage elsewhere
   1.157 +    my $rs = shift;
   1.158 +    my $data = "avgmedian|" . $rs->{avgmedian};
   1.159 +    $data .=   "|average|"  . $rs->{average};
   1.160 +    $data .=   "|minimum|"  . $rs->{minimum};
   1.161 +    $data .=   "|maximum|"  . $rs->{maximum};
   1.162 +    $_ = $rs->as_string;
   1.163 +    s/^\s+//gs;
   1.164 +    s/\s+\n$//gs;
   1.165 +    s/\s*\n/\|/gs; # fold newlines
   1.166 +    s/\|\s+/\|/gs; 
   1.167 +    s/\s+/;/gs;
   1.168 +    return $data . ":" . $_;
   1.169 +}
   1.170 +
   1.171 +#
   1.172 +# handle the request
   1.173 +#
   1.174 +my $request = new CGI::Request;
   1.175 +my $id = $request->param('id'); #XXX need to check for valid parameter id
   1.176 +my $rs = URLTimingDataSet->new($id);
   1.177 +
   1.178 +print "Content-type: text/html\n\n";
   1.179 +
   1.180 +# This sucks: we'll let the test time out to avoid crash-on-shutdown bugs
   1.181 +print "<html><body onload='window.close();'>";
   1.182 +#
   1.183 +# dump some stats for tinderbox to snarf
   1.184 +#
   1.185 +print "<script>\n";
   1.186 +print "if (window.dump) dump('";
   1.187 +print "Starting Page Load Test\\n\\\n";
   1.188 +print "Test id: $id\\n\\\n";
   1.189 +print "Avg. Median : ", $rs->{avgmedian}, " msec\\n\\\n";
   1.190 +print "Average     : ", $rs->{average}, " msec\\n\\\n";
   1.191 +print "Minimum     : ", $rs->{minimum}, " msec\\n\\\n";
   1.192 +print "Maximum     : ", $rs->{maximum}, " msec\\n\\\n";
   1.193 +print "IDX PATH                           AVG    MED    MAX    MIN  TIMES ...\\n\\\n";
   1.194 +if ($request->param('sort')) {
   1.195 +    $_ = $rs->as_string_sorted();
   1.196 +} else {
   1.197 +    $_ = $rs->as_string();
   1.198 +}
   1.199 +#
   1.200 +# Terminate raw newlines with '\n\' so we don't have an unterminated string literal.
   1.201 +#
   1.202 +s/\n/\\n\\\n/g;
   1.203 +print $_;
   1.204 +print "(tinderbox dropping follows)\\n\\\n";
   1.205 +print "_x_x_mozilla_page_load," , $rs->{avgmedian}, ",", $rs->{maximum}, ",", $rs->{minimum}, "\\n\\\n";
   1.206 +#
   1.207 +# package up this data for storage elsewhere
   1.208 +#
   1.209 +my $data = serializeDataSet($rs);
   1.210 +print "_x_x_mozilla_page_load_details,", $data, "\\n\\\n";
   1.211 +#
   1.212 +# average median
   1.213 +#
   1.214 +#print "TinderboxPrint:<a title=\"Avg. of the median per url pageload time.\" href=\"http://tegu.mozilla.org/graph/query.cgi?tbox=spider&testname=pageload&autoscale=1&days=7&avg=1\">Tp:", $rs->{avgmedian}, "ms</a>", "\\n\\\n";
   1.215 +print "');";
   1.216 +print "</script></body></html>\n";
   1.217 +
   1.218 +
   1.219 +#
   1.220 +# If this is SurfingSafari, then catch a wave and you're sitting on top of the world!!
   1.221 +# (and also blat this out to tegu, cause we got no 'dump' statement.
   1.222 +#
   1.223 +if ($request->cgi->var("HTTP_USER_AGENT") =~ /Safari/) {
   1.224 +    my %machineMap = 
   1.225 +	(
   1.226 +	 "10.169.105.26" => "boxset",
   1.227 +	 "10.169.105.21" => "pawn"
   1.228 +	 );
   1.229 +    my $ip = $request->cgi->var('REMOTE_ADDR');
   1.230 +    my $machine = $machineMap{$ip};
   1.231 +    my $res = eval q{
   1.232 +	use LWP::UserAgent;
   1.233 +	use HTTP::Request::Common qw(POST);
   1.234 +	my $ua = LWP::UserAgent->new;
   1.235 +	$ua->timeout(10); # seconds
   1.236 +	my $req = POST('http://tegu.mozilla.org/graph/collect.cgi',
   1.237 +		       [testname => 'pageload',
   1.238 +			tbox     => "$machine" . "-aux",
   1.239 +			value    => $rs->{avgmedian},
   1.240 +			data     => $data]);
   1.241 +	my $res = $ua->request($req);
   1.242 +	return $res;
   1.243 +    };
   1.244 +    if ($@) {
   1.245 +	warn "Failed to submit startup results: $@";
   1.246 +    } else {
   1.247 +	warn "Startup results submitted to server: \n",
   1.248 +	$res->status_line, "\n", $res->content, "\n";
   1.249 +    }
   1.250 +}
   1.251 +
   1.252 +
   1.253 +if ($request->param('purge')) {
   1.254 +    # now move any old stuff into archive and clean stale entries
   1.255 +    # just going with the simple approach of "whoever sees old entries
   1.256 +    # first, cleans em up, whether they 'own' them or not". Hopefully,
   1.257 +    # the default locking will be sufficient to prevent a race.
   1.258 +    close(STDOUT);
   1.259 +    sleep(1);
   1.260 +    $dbroot = "db";
   1.261 +    $dbh = DBI->connect("DBI:CSV:f_dir=./$dbroot", 
   1.262 +                        {RaiseError => 1, AutoCommit => 1})
   1.263 +	|| die "Cannot connect: " . $DBI::errstr;
   1.264 +    $arc = DBI->connect("DBI:CSV:f_dir=./$dbroot/archive", 
   1.265 +                        {RaiseError => 1, AutoCommit => 1})
   1.266 +	|| die "Cannot connect: " . $DBI::errstr;
   1.267 +    purgeStaleEntries($id);
   1.268 +    $dbh->disconnect();
   1.269 +    $arc->disconnect();
   1.270 +}
   1.271 +
   1.272 +exit 0;

mercurial