ENHACEMENT: Improved caching of permissions for improved CMS perfromance for non-admins (merged from r102278)

This commit is contained in:
Sam Minnee 2011-10-07 10:36:56 +02:00 committed by Ingo Schommer
parent d64e847534
commit 5d235fa9f7
2 changed files with 20 additions and 35 deletions

View File

@ -866,11 +866,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$extended = $this->extendedCan('canDelete', $memberID); $extended = $this->extendedCan('canDelete', $memberID);
if($extended !== null) return $extended; if($extended !== null) return $extended;
// Check cache (the can_edit_multiple call below will also do this, but this is quicker)
if(isset(self::$cache_permissions['delete'][$this->ID])) {
return self::$cache_permissions['delete'][$this->ID];
}
// Regular canEdit logic is handled by can_edit_multiple // Regular canEdit logic is handled by can_edit_multiple
$results = self::can_delete_multiple(array($this->ID), $memberID); $results = self::can_delete_multiple(array($this->ID), $memberID);
@ -942,11 +937,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
if($extended !== null) return $extended; if($extended !== null) return $extended;
if($this->ID) { if($this->ID) {
// Check cache (the can_edit_multiple call below will also do this, but this is quicker)
if(isset(self::$cache_permissions['CanEditType'][$this->ID])) {
return self::$cache_permissions['CanEditType'][$this->ID];
}
// Regular canEdit logic is handled by can_edit_multiple // Regular canEdit logic is handled by can_edit_multiple
$results = self::can_edit_multiple(array($this->ID), $memberID); $results = self::can_edit_multiple(array($this->ID), $memberID);
@ -1029,16 +1019,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$batchCallback=explode('::', $batchCallback); $batchCallback=explode('::', $batchCallback);
if(is_callable($batchCallback)) { if(is_callable($batchCallback)) {
$permissionValues = call_user_func($batchCallback, $ids, call_user_func($batchCallback, $ids, Member::currentUserID(), false);
Member::currentUserID(), false);
if(!isset(self::$cache_permissions[$permission])) {
self::$cache_permissions[$permission] = array();
}
self::$cache_permissions[$permission] = $permissionValues
+ self::$cache_permissions[$permission];
} else { } else {
user_error("SiteTree::prepopuplate_permission_cache can't calculate '$permission' " user_error("SiteTree::prepopuplate_permission_cache can't calculate '$permission' "
. "with callback '$batchCallback'", E_USER_WARNING); . "with callback '$batchCallback'", E_USER_WARNING);
@ -1069,7 +1050,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// This is the name used on the permission cache // This is the name used on the permission cache
// converts something like 'CanEditType' to 'edit'. // converts something like 'CanEditType' to 'edit'.
$cacheKey = strtolower(substr($typeField, 3, -4)); $cacheKey = strtolower(substr($typeField, 3, -4)) . "-$memberID";
// Default result: nothing editable // Default result: nothing editable
$result = array_fill_keys($ids, false); $result = array_fill_keys($ids, false);
@ -1165,14 +1146,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
} }
if(isset($combinedStageResult)) { if(isset($combinedStageResult)) {
// Cache results // Cache the results
// TODO - Caching permissions is breaking unit tests. One possible issue if(empty(self::$cache_permissions[$cacheKey])) self::$cache_permissions[$cacheKey] = array();
// is the cache needs to be flushed when permission on a page is changed, self::$cache_permissions[$cacheKey] = $combinedStageResult + self::$cache_permissions[$cacheKey];
// but this only solved some of the failing unit tests. Disabled for now.
/*foreach($combinedStageResult as $id => $val) { return $combinedStageResult;
self::$cache_permissions[$typeField][$id] = $val;
}*/
return $combinedStageResult;
} else { } else {
return array(); return array();
} }
@ -1197,15 +1175,15 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
*/ */
static function can_delete_multiple($ids, $memberID, $useCached = true) { static function can_delete_multiple($ids, $memberID, $useCached = true) {
$deletable = array(); $deletable = array();
$result = array_fill_keys($ids, false); $result = array_fill_keys($ids, false);
$cacheKey = "delete-$memberID";
// Look in the cache for values // Look in the cache for values
if($useCached && isset(self::$cache_permissions['delete'])) { if($useCached && isset(self::$cache_permissions[$cacheKey])) {
$cachedValues = array_intersect_key(self::$cache_permissions['delete'], $result); $cachedValues = array_intersect_key(self::$cache_permissions[$cacheKey], $result);
// If we can't find everything in the cache, then look up the remainder separately // If we can't find everything in the cache, then look up the remainder separately
$uncachedValues = array_diff_key($result, self::$cache_permissions['delete']); $uncachedValues = array_diff_key($result, self::$cache_permissions[$cacheKey]);
if($uncachedValues) { if($uncachedValues) {
$cachedValues = self::can_delete_multiple(array_keys($uncachedValues), $memberID, false) $cachedValues = self::can_delete_multiple(array_keys($uncachedValues), $memberID, false)
+ $cachedValues; + $cachedValues;
@ -1254,6 +1232,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return array_fill_keys($deletable, true) + array_fill_keys($ids, false); return array_fill_keys($deletable, true) + array_fill_keys($ids, false);
} }
/** /**
* Collate selected descendants of this page. * Collate selected descendants of this page.
* *
@ -2707,6 +2686,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
self::$cache_permissions = array(); self::$cache_permissions = array();
} }
static function on_db_reset() {
self::$cache_permissions = array();
}
} }
?> ?>

View File

@ -504,6 +504,8 @@ class SiteTreeTest extends SapphireTest {
$page->CanEditType = 'OnlyTheseUsers'; $page->CanEditType = 'OnlyTheseUsers';
$page->EditorGroups()->add($this->idFromFixture('Group', 'editors')); $page->EditorGroups()->add($this->idFromFixture('Group', 'editors'));
$page->write(); $page->write();
// Clear permission cache
SiteTree::on_db_reset();
// Confirm that Member.editor can now edit the page // Confirm that Member.editor can now edit the page
$this->objFromFixture('Member','editor')->logIn(); $this->objFromFixture('Member','editor')->logIn();