Commit af8cc34f authored by Leigh Stoller's avatar Leigh Stoller

Speed up the instantiate page response time, it was taking forever!

1. Okay, 10-15 seconds for me, which is the same as forever.

2. Do not sort in PHP, sort in javascript, let the client burn those
   cycles instead of poor overworked boss.

3. Store global lastused/usecount in the apt_profiles table so that we
   do not have to compute it every time for profile.

4. Compute the user's lastused/usecount for each profile in a single
   query and create local array. Cuts out 100s of queries.
parent 057a12be
......@@ -1695,7 +1695,21 @@ sub Publish($)
$self->{'DBROW'}->{'published'} = time();
return 0;
}
#
# Set the lastused datetime and usecount for the Picker.
#
sub BumpLastUsed($)
{
my ($self) = @_;
my $profileid = $self->profileid();
return -1
if (! DBQueryWarn("update apt_profiles set ".
" lastused=now(),usecount=usecount+1 ".
"where profileid='$profileid'"));
return 0;
}
#
......
......@@ -927,6 +927,8 @@ foreach my $aggregate_urn (@aggregate_urns) {
# To keep stuff happy until multisite support finished.
$instance->Update({'aggregate_urn' => $aggregate_urns[0]});
# Officially used now. Even if it fails later.
$profile->BumpLastUsed();
print STDERR "\n";
print STDERR "User: $user_urn\n";
......
......@@ -471,6 +471,8 @@ CREATE TABLE `apt_profiles` (
`nodelete` tinyint(1) NOT NULL default '0',
`locked` datetime default NULL,
`locker_pid` int(11) default '0',
`lastused` datetime default NULL,
`usecount` int(11) default '0',
PRIMARY KEY (`profileid`),
UNIQUE KEY `pidname` (`pid_idx`,`name`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
......
use strict;
use libdb;
use APT_Profile;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBSlotExists("apt_profiles", "lastused")) {
DBQueryFatal("alter table apt_profiles add " .
" `lastused` datetime default NULL");
}
if (!DBSlotExists("apt_profiles", "usecount")) {
DBQueryFatal("alter table apt_profiles add " .
" `usecount` int(11) default '0'");
}
my $query_result =
DBQueryFatal("select profileid from apt_profiles");
while (my ($profileid) = $query_result->fetchrow_array()) {
my $profile = APT_Profile->Lookup($profileid);
next
if (!defined($profile));
my $profile_id = $profile->profileid();
my $count = 0;
my $lastused = "null";
my $count_result =
DBQueryFatal("select ".
"(select count(profile_id) ".
" from apt_instances ".
" where profile_id='$profile_id') as count1, ".
"(select count(profile_id) ".
" from apt_instance_history ".
" where profile_id='$profile_id') as count2");
if ($count_result->numrows) {
my ($c1,$c2) = $count_result->fetchrow_array();
$count += $c1 if (defined($c1));
$count += $c2 if (defined($c2));
}
my $last_result =
DBQueryFatal("select max(created) ".
" from apt_instances ".
"where profile_id='$profile_id'");
my ($tmp) = $last_result->fetchrow_array();
if (!defined($tmp)) {
$last_result =
DBQueryFatal("select max(created) ".
" from apt_instance_history ".
"where profile_id='$profile_id'");
($tmp) = $last_result->fetchrow_array();
if (defined($tmp)) {
$lastused = "'$tmp'";
}
}
DBQueryFatal("update apt_profiles set ".
" lastused=$lastused,usecount=$count ".
"where profileid='$profile_id'");
}
return 0;
}
# Local Variables:
# mode:perl
# End:
......@@ -977,4 +977,54 @@ function SpitAggregateStatus() {
echo "</script>\n";
}
#
# Find usage info for user for the epoch, rather then looking up per
# profile. Much faster.
#
function UserUsageInfo($user) {
$user_idx = $user->idx();
$results = array();
$query_result =
DBQueryFatal("select profile_id,count(profile_id), ".
" max(UNIX_TIMESTAMP(created)) ".
" from apt_instances ".
" where creator_idx='$user_idx' ".
" group by profile_id");
while ($row = mysql_fetch_array($query_result)) {
$profile_id = $row[0];
$count = $row[1];
$lastused = $row[2];
$results[$profile_id] = array("count" => $count,
"lastused" => $lastused);
}
$query_result =
DBQueryFatal("select profile_id,count(profile_id), ".
" max(UNIX_TIMESTAMP(created)) ".
" from apt_instance_history ".
" where creator_idx='$user_idx' ".
" group by profile_id");
while ($row = mysql_fetch_array($query_result)) {
$profile_id = $row[0];
$count = $row[1];
$lastused = $row[2];
if (!array_key_exists($profile_id, $results)) {
$results[$profile_id] = array("count" => $count,
"lastused" => $lastused);
}
else {
$result = $results[$profile_id];
$result["count"] += $count;
if ($lastused > $result["lastused"]) {
$result["lastused"] = $lastused;
}
}
}
return $results;
}
?>
......@@ -281,16 +281,40 @@ else {
#
# Rebuild the array with extra info for the profile picker.
#
if (isset($this_user)) {
$usageinfo = UserUsageInfo($this_user);
}
$tmp_array = array();
while (list ($uuid, $title) = each ($profile_array)) {
$tmp = Profile::Lookup($uuid);
if ($tmp) {
list ($lastused, $count) = $tmp->UsageInfo($this_user);
if ($lastused == 0) {
list ($unused, $count) = $tmp->UsageInfo(null);
if (1) {
# If profile never used, no need to ask if user has used it.
if (!$tmp->usecount()) {
$count = $lastused = 0;
}
elseif (isset($this_user)) {
$profileid = $tmp->profileid();
if (array_key_exists($profileid, $usageinfo)) {
$count = $usageinfo[$profileid]["count"];
$lastused = $usageinfo[$profileid]["lastused"];
}
else {
# Use global count instead.
$count = $tmp->usecount();
$lastused = 0;
}
}
else {
# Guest user; just use the global usage count.
$count = $tmp->usecount();
$lastused = 0;
}
}
else {
$lastused = time();
$count = 0;
}
$tmp_array[$uuid] =
array("name" => $tmp->name(),
"project" => $tmp->pid(),
......@@ -301,30 +325,8 @@ while (list ($uuid, $title) = each ($profile_array)) {
"usecount" => $count);
}
}
#
# Now we want to order the list.
#
if ($this_user) {
uasort($tmp_array, function($a, $b) {
if ($a["lastused"] == $b["lastused"]) {
return 0;
}
return ($a["lastused"] > $b["lastused"]) ? -1 : 1;
});
}
else {
uasort($tmp_array, function($a, $b) {
if ($a["usecount"] == $b["usecount"]) {
return 0;
}
return ($a["usecount"] > $b["usecount"]) ? -1 : 1;
});
}
$profile_array = $tmp_array;
#TBERROR(print_r($profile_array, true), 0);
function SPITFORM($formfields, $newuser, $errors)
{
global $TBBASE, $APTMAIL, $ISAPT, $ISCLOUD, $ISPNET, $PORTAL_NAME;
......
......@@ -77,8 +77,25 @@ $(function ()
projlist = decodejson('#projects-json');
}
profilelist = decodejson('#profiles-json');
var profileToArray = _.pairs(profilelist);
/*
* Sort the entire list by recently used if a registered user,
* else just the use count.
*/
if (registered) {
profileToArray = _.sortBy(profileToArray, function (value) {
return value[1].lastused;
});
}
else {
profileToArray = _.sortBy(profileToArray, function (value) {
return value[1].usecount;
});
}
// Note that sortBy orders by ascending, so reverse.
profileToArray = profileToArray.reverse();
var recentlist = _.filter(profileToArray, function(value) {
return value[1]['usecount'] > 0;
});
......@@ -88,14 +105,8 @@ $(function ()
neverUsed = 1;
recentlist = profileToArray;
}
// Note that sortBy orders by ascending, so the most recent
// are at the end of the array.
recentlist = _.sortBy(recentlist, function(obj) {
return obj[1].lastused;
});
recentlist = _.last(recentlist, recentcount);
recentlist = _.first(recentlist, recentcount);
_.each(recentlist, function(obj, key) {
if (window.ISPNET) {
if (_.contains(psysprojlist, obj[1].project)) {
......@@ -108,7 +119,7 @@ $(function ()
}
}
});
var projcategories = MakeProfileCategories(profilelist);
var projcategories = MakeProfileCategories(profileToArray);
// Fire this off right away.
if (window.REGISTERED) {
......@@ -427,7 +438,10 @@ $(function ()
// This section should probably be rethought as it's not very clean.
// Didn't have time to refactor for initial release.
_.each(profilelist, function(obj, key) {
_.each(profiles, function(obj, key) {
key = obj[0];
obj = obj[1];
var isSystem = (window.ISPNET && _.contains(psysprojlist, obj.project)) || (!window.ISPNET &&_.contains(sysprojlist, obj.project))
if (obj.favorite == 1) {
if (isSystem ) {
......
......@@ -134,6 +134,8 @@ class Profile
function repohash() { return $this->field('repohash'); }
function repokey() { return $this->field('repokey'); }
function webtask_id() { return $this->field('webtask_id'); }
function lastused() { return $this->field('lastused'); }
function usecount() { return $this->field('usecount'); }
function profile_disabled() { return $this->field('profile_disabled'); }
function parent_profileid() { return $this->field('parent_profileid'); }
function parent_version() { return $this->field('parent_version'); }
......
......@@ -511,7 +511,7 @@
<span class='category_collapsable expanded'></span>
</span>
<ul class='list-category' id='recently_used'>
<% for (var i = recent.length-1; i >= 0; i--) {
<% for (var i = 0; i < recent.length; i++) {
var key = recent[i][0]; var value = recent[i][1]; %>
<li class='list-group-item profile-item clearfix'
value='<%- key %>' name='<%- value.name %>'><%- value.name %>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment