From b46be6adf4927bccbb719f677198c71d8fc440f2 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Wed, 10 Oct 2012 12:41:04 +0800 Subject: [PATCH] MDL-35339 Better cache reset for get_fast_modinfo(), allow exec get_fast_modinfo($courseid) --- course/lib.php | 36 +++++++---------- course/tests/courselib_test.php | 8 ---- lib/completionlib.php | 4 +- lib/deprecatedlib.php | 23 +++++------ lib/modinfolib.php | 56 ++++++++++++++++++-------- lib/phpunit/classes/data_generator.php | 5 +-- lib/phpunit/classes/util.php | 3 +- lib/tests/conditionlib_test.php | 10 +---- 8 files changed, 72 insertions(+), 73 deletions(-) diff --git a/course/lib.php b/course/lib.php index 33786e18d55..1919f797102 100644 --- a/course/lib.php +++ b/course/lib.php @@ -2695,21 +2695,24 @@ function add_course_module($mod) { /** * Creates missing course section(s) and rebuilds course cache * - * @param stdClass $course course object + * @param int|stdClass $courseorid course id or course object * @param int|array $sections list of relative section numbers to create * @return bool if there were any sections created */ -function course_create_sections_if_missing(&$course, $sections) { +function course_create_sections_if_missing($courseorid, $sections) { global $DB; if (!is_array($sections)) { $sections = array($sections); } - $existing = array_keys(get_fast_modinfo($course)->get_section_info_all()); + $existing = array_keys(get_fast_modinfo($courseorid)->get_section_info_all()); + if (is_object($courseorid)) { + $courseorid = $courseorid->id; + } $coursechanged = false; foreach ($sections as $sectionnum) { if (!in_array($sectionnum, $existing)) { $cw = new stdClass(); - $cw->course = $course->id; + $cw->course = $courseorid; $cw->section = $sectionnum; $cw->summary = ''; $cw->summaryformat = FORMAT_HTML; @@ -2719,9 +2722,7 @@ function course_create_sections_if_missing(&$course, $sections) { } } if ($coursechanged) { - rebuild_course_cache($course->id, true); - $course->modinfo = null; - $course->sectioncache = null; + rebuild_course_cache($courseorid, true); } return $coursechanged; } @@ -2745,17 +2746,8 @@ function course_add_cm_to_section($courseorid, $modid, $sectionnum, $beforemod = if (is_object($beforemod)) { $beforemod = $beforemod->id; } - if (is_object($courseorid)) { - $course = &$courseorid; - } else { - if (isset($COURSE->id) && $COURSE->id == $courseorid) { - $course = &$COURSE; - } else { - $course = $DB->get_record('course', array('id' => $courseorid), '*', MUST_EXIST); - } - } - course_create_sections_if_missing($course, $sectionnum); - $section = get_fast_modinfo($course)->get_section_info($sectionnum); + course_create_sections_if_missing($courseorid, $sectionnum); + $section = get_fast_modinfo($courseorid)->get_section_info($sectionnum); $modarray = explode(",", trim($section->sequence)); if (empty($modarray)) { $newsequence = "$modid"; @@ -2768,9 +2760,11 @@ function course_add_cm_to_section($courseorid, $modid, $sectionnum, $beforemod = } $DB->set_field("course_sections", "sequence", $newsequence, array("id" => $section->id)); $DB->set_field('course_modules', 'section', $section->id, array('id' => $modid)); - rebuild_course_cache($course->id, true); - $course->modinfo = null; - $course->sectioncache = null; + if (is_object($courseorid)) { + rebuild_course_cache($courseorid->id, true); + } else { + rebuild_course_cache($courseorid, true); + } return $section->id; // Return course_sections ID that was used. } diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php index 59579661061..c96441491fb 100644 --- a/course/tests/courselib_test.php +++ b/course/tests/courselib_test.php @@ -302,10 +302,6 @@ class courselib_testcase extends advanced_testcase { $course = $this->getDataGenerator()->create_course(array('numsections'=>5)); $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id)); - // reset cache inside $course because $course is not passed to create_module - $course->modinfo = null; - $course->sectioncache = null; - $cms = get_fast_modinfo($course)->get_cms(); $cm = reset($cms); @@ -314,10 +310,6 @@ class courselib_testcase extends advanced_testcase { moveto_module($cm, $section3); - // reset cache inside $course because $course is not passed to moveto_module - $course->modinfo = null; - $course->sectioncache = null; - $modinfo = get_fast_modinfo($course); $this->assertTrue(empty($modinfo->sections[0])); $this->assertFalse(empty($modinfo->sections[3])); diff --git a/lib/completionlib.php b/lib/completionlib.php index 4d6ea823aa2..41b79211f99 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -971,8 +971,8 @@ class completion_info { if ($data->userid == $USER->id) { $SESSION->completioncache[$cm->course][$cm->id] = $data; - $reset = 'reset'; - get_fast_modinfo($reset); + // reset modinfo for user (no need to call rebuild_course_cache()) + get_fast_modinfo($cm->course, 0, true); } } diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 8293a2ef3f2..2e98925ee5c 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -2937,13 +2937,13 @@ function get_generic_section_name($format, stdClass $section) { * from 2.4 $section may also be just the field course_sections.section * * If you need the list of all sections it is more efficient to get this data by calling - * $modinfo = get_fast_modinfo($course); + * $modinfo = get_fast_modinfo($courseorid); * $sections = $modinfo->get_section_info_all() * {@link get_fast_modinfo()} * {@link course_modinfo::get_section_info_all()} * * Information about one section (instance of section_info): - * get_fast_modinfo($course)->get_sections_info($section) + * get_fast_modinfo($courseorid)->get_sections_info($section) * {@link course_modinfo::get_section_info()} * * @deprecated since 2.4 @@ -2954,8 +2954,7 @@ function get_generic_section_name($format, stdClass $section) { function get_all_sections($courseid) { global $DB; debugging('get_all_sections() is deprecated. See phpdocs for this function', DEBUG_DEVELOPER); - $course = $DB->get_record('course', array('id' => $courseid)); - return get_fast_modinfo($course)->get_section_info_all(); + return get_fast_modinfo($courseid)->get_section_info_all(); } /** @@ -2974,8 +2973,7 @@ function get_all_sections($courseid) { function add_mod_to_section($mod, $beforemod=NULL) { debugging('Function add_mod_to_section() is deprecated, please use course_add_cm_to_section()', DEBUG_DEVELOPER); global $DB; - $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); - return course_add_cm_to_section($course, $mod->coursemodule, $mod->section, $beforemod); + return course_add_cm_to_section($mod->course, $mod->coursemodule, $mod->section, $beforemod); } /** @@ -2984,14 +2982,14 @@ function add_mod_to_section($mod, $beforemod=NULL) { * Function get_all_mods() is deprecated in 2.4 * Instead of: * - * get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused); + * get_all_mods($courseid, $mods, $modnames, $modnamesplural, $modnamesused); * * please use: * - * $mods = get_fast_modinfo($course)->get_cms(); + * $mods = get_fast_modinfo($courseorid)->get_cms(); * $modnames = get_module_types_names(); * $modnamesplural = get_module_types_names(true); - * $modnamesused = get_fast_modinfo($course)->get_used_module_names(); + * $modnamesused = get_fast_modinfo($courseorid)->get_used_module_names(); * * * @deprecated since 2.4 @@ -3008,8 +3006,7 @@ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modname global $COURSE; $modnames = get_module_types_names(); $modnamesplural= get_module_types_names(true); - $course = ($courseid==$COURSE->id) ? $COURSE : $DB->get_record('course',array('id'=>$courseid)); - $modinfo = get_fast_modinfo($course); + $modinfo = get_fast_modinfo($courseid); $mods = $modinfo->get_cms(); $modnamesused = $modinfo->get_used_module_names(); } @@ -3018,9 +3015,9 @@ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modname * Returns course section - creates new if does not exist yet * * This function is deprecated. To create a course section call: - * course_create_sections_if_missing($course, $sections); + * course_create_sections_if_missing($courseorid, $sections); * to get the section call: - * get_fast_modinfo($course)->get_section_info($sectionnum); + * get_fast_modinfo($courseorid)->get_section_info($sectionnum); * * @see course_create_sections_if_missing() * @see get_fast_modinfo() diff --git a/lib/modinfolib.php b/lib/modinfolib.php index d24ec6dff73..405fd7bfa34 100644 --- a/lib/modinfolib.php +++ b/lib/modinfolib.php @@ -1216,16 +1216,14 @@ class cm_info extends stdClass { * Returns reference to full info about modules in course (including visibility). * Cached and as fast as possible (0 or 1 db query). * - * @global object - * @global object - * @global moodle_database * @uses MAX_MODINFO_CACHE_SIZE - * @param mixed $course object or 'reset' string to reset caches, modinfo may be updated in db - * @param int $userid Defaults to current user id - * @return course_modinfo Module information for course, or null if resetting + * @param int|stdClass $courseorid object or 'reset' string to reset caches, modinfo may be updated in db + * @param int $userid Set 0 (default) for current user + * @param bool $resetonly whether we want to get modinfo or just reset the cache + * @return course_modinfo|null Module information for course, or null if resetting */ -function get_fast_modinfo(&$course, $userid=0) { - global $CFG, $USER, $DB; +function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) { + global $CFG, $USER; require_once($CFG->dirroot.'/course/lib.php'); if (!empty($CFG->enableavailability)) { @@ -1234,17 +1232,45 @@ function get_fast_modinfo(&$course, $userid=0) { static $cache = array(); - if ($course === 'reset') { - $cache = array(); + // compartibility with syntax prior to 2.4: + if ($courseorid === 'reset') { + debugging("Using the string 'reset' as the first argument of get_fast_modinfo() is deprecated. Use get_fast_modinfo(0,0,true) instead.", DEBUG_DEVELOPER); + $courseorid = 0; + $resetonly = true; + } + + if (is_object($courseorid)) { + $course = $courseorid; + } else { + $course = (object)array('id' => $courseorid, 'modinfo' => null, 'sectioncache' => null); + } + + // Function is called with $reset = true + if ($resetonly) { + if (isset($course->id) && $course->id > 0) { + $cache[$course->id] = false; + } else { + foreach (array_keys($cache) as $key) { + $cache[$key] = false; + } + } return null; } + // Function is called with $reset = false, retrieve modinfo if (empty($userid)) { $userid = $USER->id; } - if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) { - return $cache[$course->id]; + if (array_key_exists($course->id, $cache)) { + if ($cache[$course->id] === false) { + // this course has been recently reset, do not rely on modinfo and sectioncache in $course + $course->modinfo = null; + $course->sectioncache = null; + } else if ($cache[$course->id]->userid == $userid) { + // this course's modinfo for the same user was recently retrieved, return cached + return $cache[$course->id]; + } } if (!property_exists($course, 'modinfo')) { @@ -1302,8 +1328,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) { $COURSE->sectioncache = null; } // reset the fast modinfo cache - $reset = 'reset'; - get_fast_modinfo($reset); + get_fast_modinfo($courseid, 0, true); return; } @@ -1331,8 +1356,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) { } $rs->close(); // reset the fast modinfo cache - $reset = 'reset'; - get_fast_modinfo($reset); + get_fast_modinfo($courseid, 0, true); } diff --git a/lib/phpunit/classes/data_generator.php b/lib/phpunit/classes/data_generator.php index 98fecbe0920..32ab7887614 100644 --- a/lib/phpunit/classes/data_generator.php +++ b/lib/phpunit/classes/data_generator.php @@ -400,9 +400,8 @@ EOD; throw new coding_exception('section must be present in phpunit_util::create_course_section() $record'); } - $course = $DB->get_record('course', array('id' => $record['course']), '*', MUST_EXIST); - course_create_sections_if_missing($course, $record['section']); - return get_fast_modinfo($course)->get_section_info($record['section']); + course_create_sections_if_missing($record['course'], $record['section']); + return get_fast_modinfo($record['course'])->get_section_info($record['section']); } /** diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php index 0f95b2f2a5b..83b3865a044 100644 --- a/lib/phpunit/classes/util.php +++ b/lib/phpunit/classes/util.php @@ -640,8 +640,7 @@ class phpunit_util { // If file containing class is not loaded, there is no cache there anyway. format_base::reset_course_cache(0); } - $reset = 'reset'; - get_fast_modinfo($reset); + get_fast_modinfo(0, 0, true); // purge dataroot directory self::reset_dataroot(); diff --git a/lib/tests/conditionlib_test.php b/lib/tests/conditionlib_test.php index b4e7cee0dca..6079b6a108a 100644 --- a/lib/tests/conditionlib_test.php +++ b/lib/tests/conditionlib_test.php @@ -43,10 +43,6 @@ class conditionlib_testcase extends advanced_testcase { $CFG->enablecompletion = 1; $user = $this->getDataGenerator()->create_user();; $this->setUser($user); - - // Reset modinfo cache before each request - $reset = 'reset'; - get_fast_modinfo($reset); } function test_constructor() { @@ -276,8 +272,7 @@ class conditionlib_testcase extends advanced_testcase { )); // Okay sweet, now get modinfo - $course = $DB->get_record('course',array('id'=>$courseid)); - $modinfo=get_fast_modinfo($course); + $modinfo=get_fast_modinfo($courseid); // Test basic data $this->assertEquals(1,$modinfo->cms[$cmid1]->showavailability); @@ -327,8 +322,7 @@ class conditionlib_testcase extends advanced_testcase { rebuild_course_cache($courseid, true); // Okay sweet, now get modinfo - $course = $DB->get_record('course', array('id' => $courseid)); - $modinfo = get_fast_modinfo($course); + $modinfo = get_fast_modinfo($courseid); // Test basic data $section1 = $modinfo->get_section_info(1);