MDL-38541 Make sure course cache is cleared properly during upgrade
authorMarina Glancy <marina@moodle.com>
Tue, 9 Apr 2013 01:09:47 +0000 (11:09 +1000)
committerMarina Glancy <marina@moodle.com>
Tue, 9 Apr 2013 01:31:18 +0000 (11:31 +1000)
- Core upgrade MUST NOT call rebuild_course_cache() at all - update DB directly instead
- Plugins MUST call rebuild_course_cache(.., TRUE) for clearing the course cache and can not update DB directly
- Plugins MUST NOT call rebuild_course_cache() unless for clearing the cache
- Created function upgrade_ensure_not_running() to be included in other functions that can not be used during upgrade

lang/en/error.php
lib/db/upgrade.php
lib/modinfolib.php
lib/setuplib.php
mod/label/db/upgrade.php

index 622b247..66fc80a 100644 (file)
@@ -74,6 +74,7 @@ $string['cannoteditcommentexpired'] = 'You can\'t edit this. The time has expire
 $string['cannoteditpostorblog'] = 'You cannot post or edit blogs';
 $string['cannoteditsiteform'] = 'You cannot edit the site course using this form';
 $string['cannotedityourprofile'] = 'Sorry, you cannot edit own profile';
+$string['cannotexecduringupgrade'] = 'Cannot be executed during upgrade';
 $string['cannotfindcategory'] = 'Cannot find category record from database by ID - {$a}';
 $string['cannotfindcomponent'] = 'Cannot find component';
 $string['cannotfindcontext'] = 'Could not find context';
index 52a0839..ff8f1df 100644 (file)
@@ -1460,7 +1460,7 @@ function xmldb_main_upgrade($oldversion) {
 
     if ($oldversion < 2012111200.01) {
         // Force the rebuild of the cache of every courses, some cached information could contain wrong icon references.
-        rebuild_course_cache();
+        $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ?', array(null, null));
 
         // Main savepoint reached.
         upgrade_main_savepoint(true, 2012111200.01);
@@ -1665,7 +1665,7 @@ function xmldb_main_upgrade($oldversion) {
         $DB->delete_records('course_sections_avail_fields', array('userfield' => 'interests'));
         $DB->delete_records('course_modules_avail_fields', array('userfield' => 'interests'));
         // Clear course cache (will be rebuilt on first visit) in case of changes to these.
-        rebuild_course_cache(0, true);
+        $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ?', array(null, null));
 
         upgrade_main_savepoint(true, 2013022600.00);
     }
index f575761..f099328 100644 (file)
@@ -1331,11 +1331,6 @@ class cm_info extends stdClass {
  */
 function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) {
     global $CFG, $USER;
-    require_once($CFG->dirroot.'/course/lib.php');
-
-    if (!empty($CFG->enableavailability)) {
-        require_once($CFG->libdir.'/conditionlib.php');
-    }
 
     static $cache = array();
 
@@ -1346,6 +1341,11 @@ function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) {
         $resetonly = true;
     }
 
+    // Function get_fast_modinfo() can never be called during upgrade unless it is used for clearing cache only.
+    if (!$resetonly) {
+        upgrade_ensure_not_running();
+    }
+
     if (is_object($courseorid)) {
         $course = $courseorid;
     } else {
@@ -1412,6 +1412,11 @@ function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) {
 function rebuild_course_cache($courseid=0, $clearonly=false) {
     global $COURSE, $SITE, $DB, $CFG;
 
+    // Function rebuild_course_cache() can not be called during upgrade unless it's clear only.
+    if (!$clearonly && !upgrade_ensure_not_running(true)) {
+        $clearonly = true;
+    }
+
     // Destroy navigation caches
     navigation_cache::destroy_volatile_caches();
 
@@ -1422,8 +1427,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) {
 
     if ($clearonly) {
         if (empty($courseid)) {
-            $DB->set_field('course', 'modinfo', null);
-            $DB->set_field('course', 'sectioncache', null);
+            $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ?', array(null, null));
         } else {
             // Clear both fields in one update
             $resetobj = (object)array('id' => $courseid, 'modinfo' => null, 'sectioncache' => null);
@@ -1701,6 +1705,7 @@ class section_info implements IteratorAggregate {
      */
     public function __construct($data, $number, $courseid, $sequence, $modinfo, $userid) {
         global $CFG;
+        require_once($CFG->dirroot.'/course/lib.php');
 
         // Data that is always present
         $this->_id = $data->id;
@@ -1738,6 +1743,7 @@ class section_info implements IteratorAggregate {
 
         // Availability data
         if (!empty($CFG->enableavailability)) {
+            require_once($CFG->libdir. '/conditionlib.php');
             // Get availability information
             $ci = new condition_info_section($this);
             $this->_available = $ci->is_available($this->_availableinfo, true,
index e825844..164d814 100644 (file)
@@ -1181,6 +1181,30 @@ function redirect_if_major_upgrade_required() {
     }
 }
 
+/**
+ * Makes sure that upgrade process is not running
+ *
+ * To be inserted in the core functions that can not be called by pluigns during upgrade.
+ * Core upgrade should not use any API functions at all.
+ * See {@link http://docs.moodle.org/dev/Upgrade_API#Upgrade_code_restrictions}
+ *
+ * @throws moodle_exception if executed from inside of upgrade script and $warningonly is false
+ * @param bool $warningonly if true displays a warning instead of throwing an exception
+ * @return bool true if executed from outside of upgrade process, false if from inside upgrade process and function is used for warning only
+ */
+function upgrade_ensure_not_running($warningonly = false) {
+    global $CFG;
+    if (!empty($CFG->upgraderunning)) {
+        if (!$warningonly) {
+            throw new moodle_exception('cannotexecduringupgrade');
+        } else {
+            debugging(get_string('cannotexecduringupgrade', 'error'), DEBUG_DEVELOPER);
+            return false;
+        }
+    }
+    return true;
+}
+
 /**
  * Function to check if a directory exists and by default create it if not exists.
  *
index 576cd99..166de40 100644 (file)
@@ -70,8 +70,7 @@ function xmldb_label_upgrade($oldversion) {
             $courses = $DB->get_fieldset_sql('SELECT DISTINCT course '.
                 'FROM {course_modules} WHERE module=?', array($modid));
             foreach ($courses as $courseid) {
-                $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ? '.
-                        'WHERE id = ?', array(null, null, $courseid));
+                rebuild_course_cache($courseid, true);
             }
         }