Skip to content
Snippets Groups Projects
Commit bea99ae3 authored by aydreeihn's avatar aydreeihn
Browse files

Update Thread Events in Batches

Avoid php timeouts when upgrading databases with large amounts of data by updating Thread Events in batches.
parent ebca2f9a
No related branches found
No related tags found
No related merge requests found
...@@ -18,6 +18,23 @@ CREATE TABLE `%TABLE_PREFIX%event` ( ...@@ -18,6 +18,23 @@ CREATE TABLE `%TABLE_PREFIX%event` (
UNIQUE KEY `name` (`name`) UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `%TABLE_PREFIX%event` (`id`, `name`, `description`)
VALUES
(1,'created',''),
(2,'closed',''),
(3,'reopened',''),
(4,'assigned',''),
(5,'released',''),
(6,'transferred',''),
(7,'referred',''),
(8,'overdue',''),
(9,'edited',''),
(10,'viewed',''),
(11,'error',''),
(12,'collab',''),
(13,'resent',''),
(14,'deleted','');
-- Add event_id column to thread_events -- Add event_id column to thread_events
ALTER TABLE `%TABLE_PREFIX%thread_event` ALTER TABLE `%TABLE_PREFIX%thread_event`
ADD `event_id` int(11) unsigned AFTER `thread_id`; ADD `event_id` int(11) unsigned AFTER `thread_id`;
......
...@@ -2,27 +2,141 @@ ...@@ -2,27 +2,141 @@
class EventEnumRemoval extends MigrationTask { class EventEnumRemoval extends MigrationTask {
var $description = "Remove the Enum 'state' field from ThreadEvents"; var $description = "Remove the Enum 'state' field from ThreadEvents";
var $queue;
var $skipList;
var $errorList = array();
function run() { function sleep() {
// Move states into the new table as events return array('queue'=>$this->queue, 'skipList'=>$this->skipList);
$states = array('created','closed','reopened','assigned', 'released', 'transferred', 'referred', 'overdue','edited','viewed','error','collab','resent', 'deleted'); }
foreach ($states as $state) { function wakeup($stuff) {
$sql= "INSERT INTO ".EVENT_TABLE." (`name`, `description`) $this->queue = $stuff['queue'];
VALUES('". $this->skipList = $stuff['skipList'];
$state. "', '')"; while (!$this->isFinished())
db_query($sql); $this->do_batch(30, 500);
}
function run($max_time) {
$this->do_batch($max_time * 0.9, 500);
}
function isFinished() {
return $this->getQueueLength() == 0;
}
function do_batch($time=30, $max=0) {
if(!$this->queueEvents($max) || !$this->getQueueLength())
return 0;
$this->setStatus("{$this->getQueueLength()} events remaining");
$count = 0;
$start = Misc::micro_time();
while ($this->getQueueLength() && (Misc::micro_time()-$start) < $time) {
if($this->next() && $max && ++$count>=$max) {
break;
}
}
return $this->queueEvents($max);
}
function queueEvents($limit=0){
global $cfg, $ost;
# Since the queue is persistent - we want to make sure we get to empty
# before we find more events.
if(($qc=$this->getQueueLength()))
return $qc;
$sql = "SELECT this.id, this.state, that.id, that.name FROM ".THREAD_EVENT_TABLE. " this
INNER JOIN (
SELECT id, name
FROM ". EVENT_TABLE. ") that
WHERE this.state = that.name
AND event_id IS NULL";
if(($skipList=$this->getSkipList()))
$sql.= ' AND this.id NOT IN('.implode(',', db_input($skipList)).')';
if($limit && is_numeric($limit))
$sql.=' LIMIT '.$limit;
//XXX: Do a hard fail or error querying the database?
if(!($res=db_query($sql)))
return $this->error('Unable to query DB for Thread Event migration!');
// Force the log message to the database
$ost->logDebug("Thread Event Migration", 'Found '.db_num_rows($res)
.' events to migrate', true);
if(!db_num_rows($res))
return 0; //Nothing else to do!!
$this->queue = array();
while (list($id, $state, $eventId, $eventName)=db_fetch_row($res)) {
$info=array(
'id' => $id,
'state' => $state,
'eventId' => $eventId,
'eventName' => $eventName,
);
$this->enqueue($info);
} }
$sql = "UPDATE ".THREAD_EVENT_TABLE. " AS this return $this->getQueueLength();
INNER JOIN (
SELECT id, name
FROM ". EVENT_TABLE. ") AS that
SET this.event_id = that.id
WHERE this.state = that.name";
db_query($sql);
} }
function skip($eventId, $error) {
$this->skipList[] = $eventId;
return $this->error($error." (ID #$eventId)");
}
function error($what) {
global $ost;
$this->errors++;
$this->errorList[] = $what;
// Log the error but don't send the alert email
$ost->logError('Upgrader: Thread Event Migrater', $what, false);
# Assist in returning FALSE for inline returns with this method
return false;
}
function getErrors() {
return $this->errorList;
}
function getSkipList() {
return $this->skipList;
}
function enqueue($info) {
$this->queue[] = $info;
}
function getQueueLength() {
return count($this->queue);
}
function next() {
# Fetch next item -- use the last item so the array indices don't
# need to be recalculated for every shift() operation.
$info = array_pop($this->queue);
if (!$info['state']) {
# Continue with next thread event
return $this->skip($info['eventId'],
sprintf('Thread Event ID %s: State is blank', $info['eventId']));
}
db_query('update '.THREAD_EVENT_TABLE
.' set event_id='.db_input($info['eventId'])
.' where state='.db_input($info['eventName'])
.' and id='.db_input($info['id']));
return true;
}
} }
return 'EventEnumRemoval'; return 'EventEnumRemoval';
?> ?>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment