Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

MDL-29847 question preview: garbage collect old preview data.

This adds cron code which looks for question previews that have not been
touched for more than 24 hours, and deletes them.

We try to delete previews immediately. For example if the user clicks
start again, then we immediately delete their previous preview. However,
we can't do that if they just close the preview window. Hence we need
some cron code to clean up old preview that have got left lying around.

Normally, this code will not have much to do, so it will be very fast,
so we can afford to run it every cron.

This has been implemented in such a way that in future it will be easy
to add other cron code to the question bank.

Sadly, to make this work on MySQL, we require a horrible hack in the
already hacky delete_usage_records_for_mysql function.
  • Loading branch information...
commit cb12522cea72aead237cb433d4d06d4e9f1853c8 1 parent 76c9fcc
@timhunt timhunt authored
View
7 lib/cronlib.php
@@ -373,6 +373,13 @@ function cron_run() {
}
+ // Run question bank clean-up.
+ mtrace("Starting the question bank cron...", '');
+ require_once($CFG->libdir . '/questionlib.php');
+ question_bank::cron();
+ mtrace('done.');
+
+
//Run registration updated cron
mtrace(get_string('siteupdatesstart', 'hub'));
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
View
11 question/engine/bank.php
@@ -398,6 +398,17 @@ public static function fraction_options_full() {
self::ensure_fraction_options_initialised();
return self::$fractionoptionsfull;
}
+
+ /**
+ * Perform scheduled maintenance tasks relating to the question bank.
+ */
+ public static function cron() {
+ global $CFG;
+
+ // Delete any old question preview that got left in the database.
+ require_once($CFG->dirroot . '/question/previewlib.php');
+ question_preview_cron();
+ }
}
View
10 question/engine/datalib.php
@@ -758,6 +758,14 @@ public function delete_questions_usage_by_activities(qubaid_condition $qubaids)
* @param qubaid_condition $qubaids identifies which question useages to delete.
*/
protected function delete_usage_records_for_mysql(qubaid_condition $qubaids) {
+ $qubaidtest = $qubaids->usage_id_in();
+ if (strpos($qubaidtest, 'question_usages') !== false &&
+ strpos($qubaidtest, 'IN (SELECT') === 0) {
+ // This horrible hack is required by MDL-29847. It comes from
+ // http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/
+ $qubaidtest = 'IN (SELECT * FROM ' . substr($qubaidtest, 3) . ' AS hack_subquery_alias)';
+ }
+
// TODO once MDL-29589 is fixed, eliminate this method, and instead use the new $DB API.
$this->db->execute('
DELETE qu, qa, qas, qasd
@@ -765,7 +773,7 @@ protected function delete_usage_records_for_mysql(qubaid_condition $qubaids) {
JOIN {question_attempts} qa ON qa.questionusageid = qu.id
LEFT JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
LEFT JOIN {question_attempt_step_data} qasd ON qasd.attemptstepid = qas.id
- WHERE qu.id ' . $qubaids->usage_id_in(),
+ WHERE qu.id ' . $qubaidtest,
$qubaids->usage_id_in_params());
}
View
27 question/previewlib.php
@@ -313,3 +313,30 @@ function restart_preview($previewid, $questionid, $displayoptions, $context) {
redirect(question_preview_url($questionid, $displayoptions->behaviour,
$displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context));
}
+
+/**
+ * Scheduled tasks relating to question preview. Specifically, delete any old
+ * previews that are left over in the database.
+ */
+function question_preview_cron() {
+ $maxage = 24*60*60; // We delete previews that have not been touched for 24 hours.
+ $lastmodifiedcutoff = time() - $maxage;
+
+ mtrace("\n Cleaning up old question previews...", '');
+ $oldpreviews = new qubaid_join('{question_usages} quba', 'quba.id',
+ 'quba.component = :qubacomponent
+ AND NOT EXISTS (
+ SELECT 1
+ FROM {question_attempts} qa
+ JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
+ WHERE qa.questionusageid = quba.id
+ AND (qa.timemodified > :qamodifiedcutoff
+ OR qas.timecreated > :stepcreatedcutoff)
+ )
+ ',
+ array('qubacomponent' => 'core_question_preview',
+ 'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff));
+
+ question_engine::delete_questions_usage_by_activities($oldpreviews);
+ mtrace('done.');
+}
Please sign in to comment.
Something went wrong with that request. Please try again.