Commit 31a19314 authored by Aaron Wells's avatar Aaron Wells
Browse files

Even quicker way to fill in artefact paths

Bug 1400524: On a large site, the database queries to retrieve
all records from the artefact table can take too long to execute
and cause the PHP script to time out.

This optimization attempts to fix that by filling in the paths
with an iterative series of UPDATE queries instead.

Change-Id: I46c13cc97bac8a6d2bc626e3b2dc8e4cdeecd2bb
parent 2422dd9d
......@@ -1998,31 +1998,3 @@ function artefact_get_progressbar_metaartefacts($plugin, $onlythese = false) {
}
return $results;
}
/**
* Given a set of items as an associative array of id/parentid pairs, and an
* item, returns an array of the item's descendants (including the item)
*
* @param array $items Associative array
* (e.g. array(['itemid'] => 'parentid', ['itemid2'] = 'parentid2'))
* @param integer $itemid ID of the item to build the path for
*
* @return An array of IDs, from the first parent right back to the item
*/
function artefact_get_lineage($items, $itemid, $pathsofar = array()) {
// Protection against bad items list and circular references.
if (!is_array($items) || in_array($itemid, $pathsofar)) {
return $pathsofar;
}
// Add this item to the list.
array_unshift($pathsofar, $itemid);
if (!isset($items[$itemid]) || empty($items[$itemid])) {
// Finished when an item has no parent.
return $pathsofar;
}
else {
// Keep going.
return artefact_get_lineage($items, $items[$itemid], $pathsofar);
}
}
......@@ -3273,28 +3273,42 @@ function xmldb_core_upgrade($oldversion=0) {
// Set all artefacts to the path they'd have if they have no parent.
log_debug('Filling in parent artefact paths');
execute_sql("UPDATE {artefact} SET path = '/' || id WHERE parent IS NULL");
log_debug('Filling in child artefact paths');
set_time_limit(300);
$artefacts = get_records_select_menu('artefact', 'parent IS NOT NULL', null, '', 'id, parent');
set_time_limit(30);
if ($artefacts) {
$total = count($artefacts);
$done = 0;
foreach ($artefacts as $artefactid => $parent) {
$path = '/' . implode('/', artefact_get_lineage($artefacts, $artefactid));
$todb = new stdClass();
$todb->id = $artefactid;
$todb->path = $path;
update_record('artefact', $todb);
$done++;
if ($done % 10000 == 0) {
log_debug("Filling in child artefact paths: {$done}/{$total}");
set_time_limit(30);
$newcount = count_records_select('artefact', 'path IS NULL');
if ($newcount) {
$childlevel = 0;
do {
$childlevel++;
$lastcount = $newcount;
log_debug("Filling in level-{$childlevel} child artefact paths");
if (is_postgres()) {
execute_sql("
UPDATE {artefact}
SET path = p.path || '/' || {artefact}.id
FROM {artefact} p
WHERE
{artefact}.parent=p.id
AND {artefact}.path IS NULL
AND p.path IS NOT NULL
");
}
else {
execute_sql("
UPDATE
{artefact} a
INNER JOIN {artefact} p
ON a.parent = p.id
SET a.path=p.path || '/' || a.id
WHERE
a.path IS NULL
AND p.path IS NOT NULL
");
}
log_debug("Filling in child artefact paths: {$done}/{$total}");
$newcount = count_records_select('artefact', 'path IS NULL');
// There may be some bad records whose paths can't be filled in,
// so stop looping if the count stops going down.
} while ($newcount > 0 && $newcount < $lastcount);
log_debug("Done filling in child artefact paths");
}
set_time_limit(300);
}
// Make objectionable independent of view_access page.
......
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