public function test_matching_cacherev()
 {
     global $DB, $CFG;
     $this->resetAfterTest();
     $this->setAdminUser();
     $cache = cache::make('core', 'coursemodinfo');
     // Generate the course and pre-requisite module.
     $course = $this->getDataGenerator()->create_course(array('format' => 'topics', 'numsections' => 3), array('createsections' => true));
     // Make sure the cacherev is set.
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan(0, $cacherev);
     $prevcacherev = $cacherev;
     // Reset course cache and make sure cacherev is bumped up but cache is empty.
     rebuild_course_cache($course->id, true);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan($prevcacherev, $cacherev);
     $this->assertEmpty($cache->get($course->id));
     $prevcacherev = $cacherev;
     // Build course cache. Cacherev should not change but cache is now not empty. Make sure cacherev is the same everywhere.
     $modinfo = get_fast_modinfo($course->id);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertEquals($prevcacherev, $cacherev);
     $cachedvalue = $cache->get($course->id);
     $this->assertNotEmpty($cachedvalue);
     $this->assertEquals($cacherev, $cachedvalue->cacherev);
     $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
     $prevcacherev = $cacherev;
     // Little trick to check that cache is not rebuilt druing the next step - substitute the value in MUC and later check that it is still there.
     $cache->set($course->id, (object) array_merge((array) $cachedvalue, array('secretfield' => 1)));
     // Clear static cache and call get_fast_modinfo() again (pretend we are in another request). Cache should not be rebuilt.
     course_modinfo::clear_instance_cache();
     $modinfo = get_fast_modinfo($course->id);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertEquals($prevcacherev, $cacherev);
     $cachedvalue = $cache->get($course->id);
     $this->assertNotEmpty($cachedvalue);
     $this->assertEquals($cacherev, $cachedvalue->cacherev);
     $this->assertNotEmpty($cachedvalue->secretfield);
     $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
     $prevcacherev = $cacherev;
     // Rebuild course cache. Cacherev must be incremented everywhere.
     rebuild_course_cache($course->id);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan($prevcacherev, $cacherev);
     $cachedvalue = $cache->get($course->id);
     $this->assertNotEmpty($cachedvalue);
     $this->assertEquals($cacherev, $cachedvalue->cacherev);
     $modinfo = get_fast_modinfo($course->id);
     $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
     $prevcacherev = $cacherev;
     // Update cacherev in DB and make sure the cache will be rebuilt on the next call to get_fast_modinfo().
     increment_revision_number('course', 'cacherev', 'id = ?', array($course->id));
     // We need to clear static cache for course_modinfo instances too.
     course_modinfo::clear_instance_cache();
     $modinfo = get_fast_modinfo($course->id);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan($prevcacherev, $cacherev);
     $cachedvalue = $cache->get($course->id);
     $this->assertNotEmpty($cachedvalue);
     $this->assertEquals($cacherev, $cachedvalue->cacherev);
     $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
     $prevcacherev = $cacherev;
     // Reset cache for all courses and make sure this course cache is reset.
     rebuild_course_cache(0, true);
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan($prevcacherev, $cacherev);
     $this->assertEmpty($cache->get($course->id));
     // Rebuild again.
     $modinfo = get_fast_modinfo($course->id);
     $cachedvalue = $cache->get($course->id);
     $this->assertNotEmpty($cachedvalue);
     $this->assertEquals($cacherev, $cachedvalue->cacherev);
     $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
     $prevcacherev = $cacherev;
     // Purge all caches and make sure cacherev is increased and data from MUC erased.
     purge_all_caches();
     $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
     $this->assertGreaterThan($prevcacherev, $cacherev);
     $this->assertEmpty($cache->get($course->id));
 }
Esempio n. 2
0
 public function test_increment_revision_number()
 {
     global $DB;
     $this->resetAfterTest();
     // Use one of the fields that are used with increment_revision_number().
     $course1 = $this->getDataGenerator()->create_course();
     $course2 = $this->getDataGenerator()->create_course();
     $DB->set_field('course', 'cacherev', 1, array());
     $record1 = $DB->get_record('course', array('id' => $course1->id));
     $record2 = $DB->get_record('course', array('id' => $course2->id));
     $this->assertEquals(1, $record1->cacherev);
     $this->assertEquals(1, $record2->cacherev);
     // Incrementing some lower value.
     $this->setCurrentTimeStart();
     increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $course1->id));
     $record1 = $DB->get_record('course', array('id' => $course1->id));
     $record2 = $DB->get_record('course', array('id' => $course2->id));
     $this->assertTimeCurrent($record1->cacherev);
     $this->assertEquals(1, $record2->cacherev);
     // Incrementing in the same second.
     $rev1 = $DB->get_field('course', 'cacherev', array('id' => $course1->id));
     $now = time();
     $DB->set_field('course', 'cacherev', $now, array('id' => $course1->id));
     increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $course1->id));
     $rev2 = $DB->get_field('course', 'cacherev', array('id' => $course1->id));
     $this->assertGreaterThan($rev1, $rev2);
     increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $course1->id));
     $rev3 = $DB->get_field('course', 'cacherev', array('id' => $course1->id));
     $this->assertGreaterThan($rev2, $rev3);
     $this->assertGreaterThan($now + 1, $rev3);
     increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $course1->id));
     $rev4 = $DB->get_field('course', 'cacherev', array('id' => $course1->id));
     $this->assertGreaterThan($rev3, $rev4);
     $this->assertGreaterThan($now + 2, $rev4);
     // Recovering from runaway revision.
     $DB->set_field('course', 'cacherev', time() + 60 * 60 * 60, array('id' => $course2->id));
     $record2 = $DB->get_record('course', array('id' => $course2->id));
     $this->assertGreaterThan(time(), $record2->cacherev);
     $this->setCurrentTimeStart();
     increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $course2->id));
     $record2b = $DB->get_record('course', array('id' => $course2->id));
     $this->assertTimeCurrent($record2b->cacherev);
     // Update all revisions.
     $DB->set_field('course', 'cacherev', 1, array());
     $this->setCurrentTimeStart();
     increment_revision_number('course', 'cacherev', '');
     $record1 = $DB->get_record('course', array('id' => $course1->id));
     $record2 = $DB->get_record('course', array('id' => $course2->id));
     $this->assertTimeCurrent($record1->cacherev);
     $this->assertEquals($record1->cacherev, $record2->cacherev);
 }
Esempio n. 3
0
/**
 * Rebuilds or resets the cached list of course activities stored in MUC.
 *
 * rebuild_course_cache() must NEVER be called from lib/db/upgrade.php.
 * At the same time course cache may ONLY be cleared using this function in
 * upgrade scripts of plugins.
 *
 * During the bulk operations if it is necessary to reset cache of multiple
 * courses it is enough to call {@link increment_revision_number()} for the
 * table 'course' and field 'cacherev' specifying affected courses in select.
 *
 * Cached course information is stored in MUC core/coursemodinfo and is
 * validated with the DB field {course}.cacherev
 *
 * @global moodle_database $DB
 * @param int $courseid id of course to rebuild, empty means all
 * @param boolean $clearonly only clear the cache, gets rebuild automatically on the fly.
 *     Recommended to set to true to avoid unnecessary multiple rebuilding.
 */
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();

    if (class_exists('format_base')) {
        // if file containing class is not loaded, there is no cache there anyway
        format_base::reset_course_cache($courseid);
    }

    $cachecoursemodinfo = cache::make('core', 'coursemodinfo');
    if (empty($courseid)) {
        // Clearing caches for all courses.
        increment_revision_number('course', 'cacherev', '');
        $cachecoursemodinfo->purge();
        course_modinfo::clear_instance_cache();
        // Update global values too.
        $sitecacherev = $DB->get_field('course', 'cacherev', array('id' => SITEID));
        $SITE->cachrev = $sitecacherev;
        if ($COURSE->id == SITEID) {
            $COURSE->cacherev = $sitecacherev;
        } else {
            $COURSE->cacherev = $DB->get_field('course', 'cacherev', array('id' => $COURSE->id));
        }
    } else {
        // Clearing cache for one course, make sure it is deleted from user request cache as well.
        increment_revision_number('course', 'cacherev', 'id = :id', array('id' => $courseid));
        $cachecoursemodinfo->delete($courseid);
        course_modinfo::clear_instance_cache($courseid);
        // Update global values too.
        if ($courseid == $COURSE->id || $courseid == $SITE->id) {
            $cacherev = $DB->get_field('course', 'cacherev', array('id' => $courseid));
            if ($courseid == $COURSE->id) {
                $COURSE->cacherev = $cacherev;
            }
            if ($courseid == $SITE->id) {
                $SITE->cachrev = $cacherev;
            }
        }
    }

    if ($clearonly) {
        return;
    }

    if ($courseid) {
        $select = array('id'=>$courseid);
    } else {
        $select = array();
        core_php_time_limit::raise();  // this could take a while!   MDL-10954
    }

    $rs = $DB->get_recordset("course", $select,'','id,'.join(',', course_modinfo::$cachedfields));
    // Rebuild cache for each course.
    foreach ($rs as $course) {
        course_modinfo::build_course_cache($course);
    }
    $rs->close();
}
Esempio n. 4
0
/**
 * Invalidates browser caches and cached data in temp.
 *
 * IMPORTANT - If you are adding anything here to do with the cache directory you should also have a look at
 * {@link phpunit_util::reset_dataroot()}
 *
 * @return void
 */
function purge_all_caches()
{
    global $CFG, $DB;
    reset_text_filters_cache();
    js_reset_all_caches();
    theme_reset_all_caches();
    get_string_manager()->reset_caches();
    core_text::reset_caches();
    if (class_exists('core_plugin_manager')) {
        core_plugin_manager::reset_caches();
    }
    // Bump up cacherev field for all courses.
    try {
        increment_revision_number('course', 'cacherev', '');
    } catch (moodle_exception $e) {
        // Ignore exception since this function is also called before upgrade script when field course.cacherev does not exist yet.
    }
    $DB->reset_caches();
    cache_helper::purge_all();
    // Purge all other caches: rss, simplepie, etc.
    clearstatcache();
    remove_dir($CFG->cachedir . '', true);
    // Make sure cache dir is writable, throws exception if not.
    make_cache_directory('');
    // This is the only place where we purge local caches, we are only adding files there.
    // The $CFG->localcachedirpurged flag forces local directories to be purged on cluster nodes.
    remove_dir($CFG->localcachedir, true);
    set_config('localcachedirpurged', time());
    make_localcache_directory('', true);
    \core\task\manager::clear_static_caches();
}
Esempio n. 5
0
 /**
  * Pre-uninstall hook.
  *
  * This is intended for disabling of plugin, some DB table purging, etc.
  *
  * NOTE: to be called from uninstall_plugin() only.
  * @private
  */
 public function uninstall_cleanup()
 {
     global $DB, $CFG;
     if (!($module = $DB->get_record('modules', array('name' => $this->name)))) {
         parent::uninstall_cleanup();
         return;
     }
     // Delete all the relevant instances from all course sections.
     if ($coursemods = $DB->get_records('course_modules', array('module' => $module->id))) {
         foreach ($coursemods as $coursemod) {
             // Do not verify results, there is not much we can do anyway.
             delete_mod_from_section($coursemod->id, $coursemod->section);
         }
     }
     // Increment course.cacherev for courses that used this module.
     // This will force cache rebuilding on the next request.
     increment_revision_number('course', 'cacherev', "id IN (SELECT DISTINCT course\n                      FROM {course_modules}\n                     WHERE module=?)", array($module->id));
     // Delete all the course module records.
     $DB->delete_records('course_modules', array('module' => $module->id));
     // Delete module contexts.
     if ($coursemods) {
         foreach ($coursemods as $coursemod) {
             \context_helper::delete_instance(CONTEXT_MODULE, $coursemod->id);
         }
     }
     // Delete the module entry itself.
     $DB->delete_records('modules', array('name' => $module->name));
     // Cleanup the gradebook.
     require_once $CFG->libdir . '/gradelib.php';
     grade_uninstalled_module($module->name);
     // Do not look for legacy $module->name . '_uninstall any more,
     // they should have migrated to db/uninstall.php by now.
     parent::uninstall_cleanup();
 }