Index: lib/accesslib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/accesslib.php,v retrieving revision 1.421.2.101 diff -u -r1.421.2.101 accesslib.php --- lib/accesslib.php 25 Mar 2009 02:37:27 -0000 1.421.2.101 +++ lib/accesslib.php 1 Apr 2009 12:03:34 -0000 @@ -160,6 +160,10 @@ require_once($CFG->dirroot.'/group/lib.php'); +if (!defined('MAX_CONTEXT_CACHE_SIZE')) { + define('MAX_CONTEXT_CACHE_SIZE', 5000); +} + $context_cache = array(); // Cache of all used context objects for performance (by level and instance) $context_cache_id = array(); // Index to above cache by id @@ -167,6 +171,28 @@ $ACCESS = array(); // cache of caps for cron user switching and has_capability for other users (==not $USER) $RDEFS = array(); // role definitions cache - helps a lot with mem usage in cron +/** + * Called after adding items to the context cache. Makes sure the context cache + * is not getting too large. This deals with situations where the system + * accidentally ends up caching every context in the system and running out + * of memory. + */ +function check_context_cache_size() { + global $context_cache, $context_cache_id; + + // If size is within the allowed limit, return + if (count($context_cache_id) < MAX_CONTEXT_CACHE_SIZE) { + return; + } + + // OK, remove 1/4 the items from cache + for ($remove = MAX_CONTEXT_CACHE_SIZE/4; $remove > 0; $remove--) { + $context = reset($context_cache_id); + unset($context_cache_id[$context->id]); + unset($context_cache[$context->contextlevel][$context->instanceid]); + } +} + function get_role_context_caps($roleid, $context) { //this is really slow!!!! - do not use above course context level! $result = array(); @@ -2467,6 +2493,7 @@ } rs_close($rs); $preloadedcourses[$courseid] = true; + check_context_cache_size(); } /** @@ -2517,6 +2544,7 @@ if (!empty($context)) { $context_cache[$contextlevel][$instance] = $context; // Cache it for later $context_cache_id[$context->id] = $context; // Cache it for later + check_context_cache_size(); } return $context; @@ -2561,6 +2589,7 @@ if (!empty($context)) { $context_cache[$contextlevel][$instance] = $context; // Cache it for later $context_cache_id[$context->id] = $context; // Cache it for later + check_context_cache_size(); } $result[$instance] = $context; @@ -2591,6 +2620,7 @@ if ($context = get_record('context', 'id', $id)) { // Update the cache and return $context_cache[$context->contextlevel][$context->instanceid] = $context; $context_cache_id[$context->id] = $context; + check_context_cache_size(); return $context; } Index: course/lib.php =================================================================== RCS file: /cvsroot/moodle/moodle/course/lib.php,v retrieving revision 1.538.2.69 diff -u -r1.538.2.69 lib.php --- course/lib.php 14 Jan 2009 04:47:21 -0000 1.538.2.69 +++ course/lib.php 1 Apr 2009 12:03:33 -0000 @@ -21,6 +21,9 @@ define('MOD_CLASS_ACTIVITY', 0); define('MOD_CLASS_RESOURCE', 1); +if (!defined('MAX_MODINFO_CACHE_SIZE')) { + define('MAX_MODINFO_CACHE_SIZE', 10); +} function make_log_url($module, $url) { switch ($module) { @@ -1176,6 +1179,11 @@ unset($cache[$course->id]); // prevent potential reference problems when switching users $cache[$course->id] = $modinfo; + // Ensure cache does not use too much RAM + if (count($cache) > MAX_MODINFO_CACHE_SIZE) { + unset($cache[reset($cache)->id]); + } + return $cache[$course->id]; } Index: mod/forum/lib.php =================================================================== RCS file: /cvsroot/moodle/moodle/mod/forum/lib.php,v retrieving revision 1.609.2.90 diff -u -r1.609.2.90 lib.php --- mod/forum/lib.php 20 Mar 2009 13:38:27 -0000 1.609.2.90 +++ mod/forum/lib.php 1 Apr 2009 12:03:35 -0000 @@ -5448,21 +5448,21 @@ switch ($context->contextlevel) { case CONTEXT_SYSTEM: // For the whole site - if ($courses = get_records('course')) { - foreach ($courses as $course) { - $subcontext = get_context_instance(CONTEXT_COURSE, $course->id); - forum_add_user_default_subscriptions($userid, $subcontext); - } + $rs = get_recordset('course', '', '', '', 'id'); + while ($course = rs_fetch_next_record($rs)) { + $subcontext = get_context_instance(CONTEXT_COURSE, $course->id); + forum_add_user_default_subscriptions($userid, $subcontext); } + rs_close($rs); break; case CONTEXT_COURSECAT: // For a whole category - if ($courses = get_records('course', 'category', $context->instanceid)) { - foreach ($courses as $course) { - $subcontext = get_context_instance(CONTEXT_COURSE, $course->id); - forum_add_user_default_subscriptions($userid, $subcontext); - } - } + $rs = get_recordset('course', 'category', $context->instanceid, '', 'id'); + while ($course = rs_fetch_next_record($rs)) { + $subcontext = get_context_instance(CONTEXT_COURSE, $course->id); + forum_add_user_default_subscriptions($userid, $subcontext); + } + rs_close($rs); if ($categories = get_records('course_categories', 'parent', $context->instanceid)) { foreach ($categories as $category) { $subcontext = get_context_instance(CONTEXT_COURSECAT, $category->id);