From a2cf7f1b8a5f8005a853c6a3eee4ad51465b132e Mon Sep 17 00:00:00 2001 From: skodak Date: Wed, 17 Oct 2007 09:19:39 +0000 Subject: [PATCH] MDL-11658 shared rdef definition - reduced memory usage in cron --- lib/accesslib.php | 64 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/accesslib.php b/lib/accesslib.php index dfa3ac4880b..ef455bb38e8 100755 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -59,7 +59,7 @@ * - has_capability_in_accessdata() * - is_siteadmin() * - get_user_access_sitewide() - * - get_user_access_bycontext() + * - load_subcontext() * - get_role_access_bycontext() * * Name conventions @@ -159,6 +159,7 @@ $context_cache_id = array(); // Index to above cache by id $DIRTYCONTEXTS = null; // dirty contexts cache $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 function get_role_context_caps($roleid, $context) { //this is really slow!!!! - do not use above course context level! @@ -358,6 +359,7 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) { // not-logged-in user or $USER object set up manually first time here load_all_capabilities(); $ACCESS = array(); // reset the cache for other users too, the dirty contexts are empty now + $RDEFS = array(); } // Load dirty contexts list if needed @@ -371,6 +373,7 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) { // and then cleanup any marks of dirtyness... at least from our short // term memory! :-) $ACCESS = array(); + $RDEFS = array(); if (defined('FULLME') && FULLME === 'cron') { load_user_accessdata($userid); @@ -404,8 +407,7 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) { error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}"); // $bt = debug_backtrace(); // error_log("bt {$bt[0]['file']} {$bt[0]['line']}"); - $USER->access = get_user_access_bycontext($USER->id, $context, - $USER->access); + load_subcontext($USER->id, $context, $USER->access); } return has_capability_in_accessdata($capability, $context, $USER->access, $doanything); } @@ -422,8 +424,7 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) { error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}"); // $bt = debug_backtrace(); // error_log("bt {$bt[0]['file']} {$bt[0]['line']}"); - $ACCESS[$userid] = get_user_access_bycontext($userid, $context, - $ACCESS[$userid]); + load_subcontext($userid, $context, $ACCESS[$userid]); } return has_capability_in_accessdata($capability, $context, $ACCESS[$userid], $doanything); } @@ -1283,9 +1284,8 @@ function get_user_access_sitewide($userid) { * @param $userid integer - the id of the user * @param $context context obj - needs path! * @param $accessdata array accessdata array - * */ -function get_user_access_bycontext($userid, $context, $accessdata=NULL) { +function load_subcontext($userid, $context, &$accessdata) { global $CFG; @@ -1298,14 +1298,6 @@ function get_user_access_bycontext($userid, $context, $accessdata=NULL) { * - below this user's RAs - limited to course level */ - // Roles already in use in this context - if (is_null($accessdata)) { - $accessdata = array(); // named list - $accessdata['ra'] = array(); - $accessdata['rdef'] = array(); - $accessdata['loaded'] = array(); - } - $base = "/" . SYSCONTEXTID; // @@ -1394,22 +1386,27 @@ function get_user_access_bycontext($userid, $context, $accessdata=NULL) { $wherelocalroles ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC "; + $newrdefs = array(); if ($rs = get_recordset_sql($sql)) { while ($rd = rs_fetch_next_record($rs)) { $k = "{$rd->path}:{$rd->roleid}"; - $accessdata['rdef'][$k][$rd->capability] = $rd->permission; + if (!array_key_exists($k, $newrdefs)) { + $newrdefs[$k] = array(); + } + $newrdefs[$k][$rd->capability] = $rd->permission; } rs_close($rs); } else { debugging('Bad SQL encountered!'); } - // TODO: compact capsets? + compact_rdefs($newrdefs); + foreach ($newrdefs as $key=>$value) { + $accessdata['rdef'][$key] =& $newrdefs[$key]; + } error_log("loaded {$context->path}"); $accessdata['loaded'][] = $context->path; - - return $accessdata; } /** @@ -1475,7 +1472,7 @@ function get_role_access_bycontext($roleid, $context, $accessdata=NULL) { return $accessdata; } -/* +/** * Load accessdata for a user * into the $ACCESS global * @@ -1483,8 +1480,6 @@ function get_role_access_bycontext($roleid, $context, $accessdata=NULL) { * to call it if you are about to run a BIG * cron run across a bazillion users. * - * TODO: share rdef tree to save mem - * */ function load_user_accessdata($userid) { global $ACCESS,$CFG; @@ -1521,10 +1516,33 @@ function load_user_accessdata($userid) { // for dirty timestamps in cron $accessdata['time'] = time(); - $ACCESS[$userid] = $accessdata; + $ACCESS[$userid] = $accessdata; + compact_rdefs($ACCESS[$userid]['rdef']); + return true; } +/** + * Use shared copy of role definistions stored in $RDEFS; + * @param array $rdefs array of role definitions in contexts + */ +function compact_rdefs(&$rdefs) { + global $RDEFS; + + /* + * This is a basic sharing only, we could also + * use md5 sums of values. The main purpose is to + * reduce mem in cron jobs - many users in $ACCESS array. + */ + + foreach ($rdefs as $key => $value) { + if (!array_key_exists($key, $RDEFS)) { + $RDEFS[$key] = $rdefs[$key]; + } + $rdefs[$key] =& $RDEFS[$key]; + } +} + /** * A convenience function to completely load all the capabilities * for the current user. This is what gets called from login, for example.