--- accesslib.php	2009-10-16 16:26:58.000000000 +0200
+++ accesslib.php.my	2009-10-16 16:28:04.000000000 +0200
@@ -159,12 +159,14 @@
 
 require_once($CFG->dirroot.'/group/lib.php');
 
-if (!defined('MAX_CONTEXT_CACHE_SIZE')) { 
-    define('MAX_CONTEXT_CACHE_SIZE', 5000);
+if (!defined('MAX_CONTEXT_CACHE_SIZE')) {
+    // define('MAX_CONTEXT_CACHE_SIZE', 5000); // moodle default
+    define('MAX_CONTEXT_CACHE_SIZE', 2500); // should be 500-3000
 }
 
 $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
+$preloadedcourses = array(); 
 
 $DIRTYCONTEXTS = null; // dirty contexts cache
 $ACCESS = array(); // cache of caps for cron user switching and has_capability for other users (==not $USER)
@@ -175,19 +177,40 @@
  * @param object $context Context object to be cached
  */
 function cache_context($context) {
-    global $context_cache, $context_cache_id;
+    global $context_cache, $context_cache_id, $preloadedcourses; 
+    static $contextcount = 0; // count($context_cache_id) is far to expensive on massive deletes
+
+    // already cached
+    if ( isset($context_cache_id[$context->id]) ){
+    	return;
+    }
 
     // If there are too many items in the cache already, remove items until
     // there is space
-    while (count($context_cache_id) >= MAX_CONTEXT_CACHE_SIZE) {
-        $first = reset($context_cache_id);
-        unset($context_cache_id[$first->id]);
-        unset($context_cache[$first->contextlevel][$first->instanceid]);
-    }
+    if ( $contextcount >= MAX_CONTEXT_CACHE_SIZE ){
+        // the php-Standard is 30 seconds, under conditions of heavy cpu load this may not be enought
+        $max_execution_time = ini_get('max_execution_time');
+        @set_time_limit($max_execution_time*2); 
+
+        while ($contextcount > (MAX_CONTEXT_CACHE_SIZE*0.8)) { // 80% Cache Fill-Factor
+            $remove = reset($context_cache_id);
+
+            // remove from $prloadedcourses too
+            if (isset($preloadedcourses[$remove->instanceid])) {
+            	unset($preloadedcourses[$remove->instanceid]);
+            }
+            unset($context_cache_id[$remove->id]);
+            unset($context_cache[$remove->contextlevel][$remove->instanceid]);
+            $contextcount--;
+        }
+
+        @set_time_limit( $max_execution_time ); // reset to old value
+     }
 
     // Add this context to the cache
     $context_cache_id[$context->id] = $context;
     $context_cache[$context->contextlevel][$context->instanceid] = $context;
+    $contextcount++;
 }
 
 function get_role_context_caps($roleid, $context) {
@@ -2280,7 +2303,7 @@
  * @return bool properly deleted
  */
 function delete_context($contextlevel, $instanceid) {
-    global $context_cache, $context_cache_id;
+    global $context_cache, $context_cache_id, $preloadedcourses;
 
     // do not use get_context_instance(), because the related object might not exist,
     // or the context does not exist yet and it would be created now
@@ -2298,6 +2321,10 @@
         // purge static context cache if entry present
         unset($context_cache[$contextlevel][$instanceid]);
         unset($context_cache_id[$context->id]);
+        // and remove from $preloadedcourses too
+        if (isset($preloadedcourses[$instanceid])) {
+            unset($preloadedcourses[$instanceid]);
+        }
 
         return $result;
     } else {
@@ -2451,11 +2478,10 @@
  * @return void
  */
 function preload_course_contexts($courseid) {
-    global $context_cache, $context_cache_id, $CFG;
+    global $context_cache, $context_cache_id, $CFG, $preloadedcourses;
 
     // Users can call this multiple times without doing any harm
-    static $preloadedcourses = array();
-    if (array_key_exists($courseid, $preloadedcourses)) {
+    if (isset($preloadedcourses[$courseid])) {
         return;
     }
 
@@ -3774,7 +3800,9 @@
             $records = array();
             while ($rec = rs_fetch_next_record($rs)) {
                 $records[$rec->id] = $rec;
-                $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+                // no direct access to cache, other ways the cachecounter will be incorrect
+                // $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+                cache_context($rec);
             }
             rs_close($rs);
             return $records;
@@ -3793,7 +3821,9 @@
             $records = array();
             while ($rec = rs_fetch_next_record($rs)) {
                 $records[$rec->id] = $rec;
-                $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+                // no direct access to cache, other ways the cachecounter will be incorrect
+                // $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+                cache_context($rec);
             }
             rs_close($rs);
             return $records;
@@ -5394,7 +5424,7 @@
  * @return void
  */
 function build_context_path($force=false, $feedback=false) {
-    global $CFG;
+    global $CFG, $preloadedcourses;
     require_once($CFG->libdir.'/ddllib.php');
 
     // System context
@@ -5570,10 +5600,11 @@
     //TODO: fix group contexts
 
     // reset static course cache - it might have incorrect cached data
-    global $context_cache, $context_cache_id;
+    global $context_cache, $context_cache_id, $preloadedcourses;
     $context_cache    = array();
     $context_cache_id = array();
-
+    // reset $prloadedcourses too
+    $preloadedcourses = array();
 }
 
 /**
