From 173839c0a647d6b7a0dba73276f2439a05cef894 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 9 Aug 2013 13:09:26 +1000 Subject: [PATCH] MDL-36789 Quick course cache integrity check for deleted modules --- lib/modinfolib.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/modinfolib.php b/lib/modinfolib.php index d48504ec640..e52af00a2e5 100644 --- a/lib/modinfolib.php +++ b/lib/modinfolib.php @@ -242,7 +242,7 @@ class course_modinfo extends stdClass { * @param int $userid User ID */ public function __construct($course, $userid) { - global $CFG, $DB; + global $CFG, $DB, $COURSE, $SITE; // Check modinfo field is set. If not, build and load it. if (empty($course->modinfo) || empty($course->sectioncache)) { @@ -287,9 +287,29 @@ class course_modinfo extends stdClass { } } - // If we haven't already preloaded contexts for the course, do it now + // If we haven't already preloaded contexts for the course, do it now. + // Modules are also cached here as long as it's the first time this course has been preloaded. preload_course_contexts($course->id); + // Quick integrity check: as a result of race conditions modinfo may not be regenerated after the change. + // It is especially dangerous if modinfo contains the deleted course module, as it results in fatal error. + // We can check it very cheap by validating the existence of module context. + if ($course->id == $COURSE->id || $course->id == $SITE->id) { + // Only verify current course (or frontpage) as pages with many courses may not have module contexts cached. + // (Uncached modules will result in a very slow verification). + foreach ($info as $mod) { + if (!context_module::instance($mod->cm, IGNORE_MISSING)) { + debugging('Course cache integrity check failed: course module with id '. $mod->cm. + ' does not have context. Rebuilding cache for course '. $course->id); + rebuild_course_cache($course->id); + $this->course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); + $info = unserialize($this->course->modinfo); + $sectioncache = unserialize($this->course->sectioncache); + break; + } + } + } + // Loop through each piece of module data, constructing it $modexists = array(); foreach ($info as $mod) {