1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-06-26 03:30:48 +03:00

ввод поддержки псевдо мульти-запросов к кешу, в дальнейшем сделать её реальной для memcache

This commit is contained in:
Mzhelskiy Maxim 2009-05-23 08:03:46 +00:00
parent 2a1f681886
commit f38ec56f31
4 changed files with 190 additions and 20 deletions

View file

@ -0,0 +1,95 @@
<?php
/**
* Dklab_Cache_Backend_MemcachedMultiload: memcached native backend
* with multi-get query support (for faster tag-based operations).
*
* Note that class uses a dirty hack to fetch the real memcache handle from
* a private property of Zend_Cache_Backend_Memcached. No chanse that ZF
* developers will do it protected in a next release...
*
* $Id$
*/
require_once "Zend/Cache/Backend/Memcached.php";
class Dklab_Cache_Backend_MemcachedMultiload extends Zend_Cache_Backend_Memcached
{
private $_handle;
/**
* Constructor.
*
* @see Zend_Cache_Backend_Memcached::__construct()
*/
public function __construct($options = array())
{
parent::__construct($options);
$this->_handle = self::_getPrivateProp($this, "_memcache");
}
/**
* Returns native handle.
*
* @return Memcache Native PHP memcache handle.
*/
protected function _getHandle()
{
return $this->_handle;
}
/**
* Loads an array of items from the memcached.
* Extends Zend_Cache_Backend_Memcached with support of multi-get feature.
*
* @param array $ids A list of IDs to be loaded.
* @param bool $doNotTestCacheValidity See parent method.
* @return array An array of values for each ID.
*/
public function multiLoad($ids, $doNotTestCacheValidity = false)
{
if (!is_array($ids)) {
Zend_Cache::throwException('multiLoad() expects parameter 1 to be array, ' . gettype($ids) . ' given');
}
if ($doNotTestCacheValidity) {
$this->_log("Zend_Cache_Backend_Memcached::load() : \$doNotTestCacheValidity=true is unsupported by the Memcached backend");
}
$tmp = $this->_getHandle()->get($ids);
if (!is_array($tmp)) {
$tmp=array($tmp);
}
foreach ($tmp as $k => $v) {
if (is_array($v)) {
$tmp[$k] = $v[0];
}
}
return $tmp;
}
/**
* Reads a private or protected property from the object.
* Unfortunately we have to use this hack, because Zend_Cache_Backend_Memcached
* does not declare $_memcache handle as protected.
*
* In PHP private properties are named with \x00 in the name.
*
* @param object $obj Object to read a property from.
* @param string $name Name of a protected or private property.
* @return mixed Property value or exception if property is not found.
*/
private static function _getPrivateProp($obj, $name)
{
$arraized = (array)$obj;
foreach ($arraized as $k => $v) {
if (substr($k, -strlen($name)) === $name) {
return $v;
}
}
throw new Exception(
"Cannot find $name property in Zend_Cache_Backend_Memcached; properties are: "
. array_map('addslashes', array_keys($arraized))
);
}
}

View file

@ -5,7 +5,7 @@
* Calls $incrementor each time the code invokes a backend call.
* This class may be used in debugging purposes.
*
* $Id: MetaForm.php 238 2008-03-17 21:07:17Z dk $
* $Id$
*/
require_once "Zend/Cache/Backend/Interface.php";
@ -32,16 +32,37 @@ class Dklab_Cache_Backend_Profiler implements Zend_Cache_Backend_Interface
{
$t0 = microtime(true);
$result = $this->_backend->load($id, $doNotTestCacheValidity);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, $id);
return $result;
}
public function multiLoad($ids, $doNotTestCacheValidity = false)
{
if (!is_array($ids)) {
Zend_Cache::throwException('multiLoad() expects parameter 1 to be array, ' . gettype($ids) . ' given');
}
if (method_exists($this->_backend, 'multiLoad')) {
$t0 = microtime(true);
$result = $this->_backend->multiLoad($ids, $doNotTestCacheValidity);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, $ids);
return $result;
}
// No multiLoad() method avalilable, so we have to emulate it to keep
// the interface consistent.
$result = array();
foreach ($ids as $i => $id) {
$result[$id] = $this->load($id, $doNotTestCacheValidity);
}
return $result;
}
public function test($id)
{
$t0 = microtime(true);
$result = $this->_backend->test($id);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, $id);
return $result;
}
@ -50,7 +71,7 @@ class Dklab_Cache_Backend_Profiler implements Zend_Cache_Backend_Interface
{
$t0 = microtime(true);
$result = $this->_backend->save($data, $id, $tags, $specificLifetime);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, $id);
return $result;
}
@ -59,7 +80,7 @@ class Dklab_Cache_Backend_Profiler implements Zend_Cache_Backend_Interface
{
$t0 = microtime(true);
$result = $this->_backend->remove($id);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, $id);
return $result;
}
@ -68,7 +89,7 @@ class Dklab_Cache_Backend_Profiler implements Zend_Cache_Backend_Interface
{
$t0 = microtime(true);
$result = $this->_backend->clean($mode, $tags);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__);
call_user_func($this->_incrementor, microtime(true) - $t0, __METHOD__, null);
return $result;
}
}

View file

@ -6,13 +6,13 @@
* increases the data read cost (the more tags are assigned to a key,
* the more read cost becomes).
*
* $Id: MetaForm.php 238 2008-03-17 21:07:17Z dk $
* $Id$
*/
require_once "Zend/Cache/Backend/Interface.php";
class Dklab_Cache_Backend_TagEmuWrapper implements Zend_Cache_Backend_Interface
{
const VERSION = "01";
const VERSION = "1.50";
private $_backend = null;
@ -34,7 +34,7 @@ class Dklab_Cache_Backend_TagEmuWrapper implements Zend_Cache_Backend_Interface
return $this->_loadOrTest($id, $doNotTestCacheValidity, false);
}
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
// Save/update tags as usual infinite keys with value of tag version.
@ -84,7 +84,6 @@ class Dklab_Cache_Backend_TagEmuWrapper implements Zend_Cache_Backend_Interface
}
/**
* Mangles the name to deny intersection of tag keys & data keys.
* Mangled tag names are NOT saved in memcache $combined[0] value,
@ -99,6 +98,22 @@ class Dklab_Cache_Backend_TagEmuWrapper implements Zend_Cache_Backend_Interface
}
/**
* The same as _mangleTag(), but mangles a list of tags.
*
* @see self::_mangleTag
* @param array $tags Tags to mangle.
* @return array List of mangled tags.
*/
private function _mangleTags($tags)
{
foreach ($tags as $i => $tag) {
$tags[$i] = $this->_mangleTag($tag);
}
return $tags;
}
/**
* Common method called from load() and test().
*
@ -121,11 +136,27 @@ class Dklab_Cache_Backend_TagEmuWrapper implements Zend_Cache_Backend_Interface
}
// Test if all tags has the same version as when the slot was created
// (i.e. still not removed and then recreated).
if (is_array($combined[0])) {
foreach ($combined[0] as $tag => $savedTagVersion) {
$actualTagVersion = $this->_backend->load($this->_mangleTag($tag));
if ($actualTagVersion !== $savedTagVersion) {
return false;
if (is_array($combined[0]) && $combined[0]) {
if (method_exists($this->_backend, 'multiLoad')) {
// If we have multiLoad(), optimize queries into one.
$allMangledTagValues = $this->_backend->multiLoad($this->_mangleTags(array_keys($combined[0])));
foreach ($combined[0] as $tag => $savedTagVersion) {
$actualTagVersion = @$allMangledTagValues[$this->_mangleTag($tag)];
if ($actualTagVersion !== $savedTagVersion) {
return false;
}
}
} else {
// Check all tags versions AND STOP IF WE FOUND AN INCONSISTENT ONE.
// Note that this optimization works fine only if $this->_backend is
// references to Dklab_Cache_Backend, but NOT via Dklab_Cache_Backend
// wrappers, because such wrappers emulate multiLoad() via multiple
// load() calls.
foreach ($combined[0] as $tag => $savedTagVersion) {
$actualTagVersion = $this->_backend->load($this->_mangleTag($tag));
if ($actualTagVersion !== $savedTagVersion) {
return false;
}
}
}
}

View file

@ -17,6 +17,7 @@
require_once(DIR_SERVER_ROOT.'/classes/lib/external/DklabCache/config.php');
require_once('Zend/Cache.php');
require_once('Cache/Backend/MemcachedMultiload.php');
require_once('Cache/Backend/TagEmuWrapper.php');
require_once('Cache/Backend/Profiler.php');
@ -73,7 +74,7 @@ class LsCache extends Module {
} elseif ($this->sCacheType==SYS_CACHE_TYPE_MEMORY) {
require_once('Zend/Cache/Backend/Memcached.php');
$aConfigMem=include(DIR_SERVER_ROOT."/config/config.memcache.php");
$oCahe = new Zend_Cache_Backend_Memcached($aConfigMem);
$oCahe = new Dklab_Cache_Backend_MemcachedMultiload($aConfigMem);
$this->oBackendCache = new Dklab_Cache_Backend_TagEmuWrapper(new Dklab_Cache_Backend_Profiler($oCahe,array($this,'CalcStats')));
} else {
throw new Exception($this->Lang_Get('system_error_cache_type').": ".$this->sCacheType." (file, memory)");
@ -100,13 +101,35 @@ class LsCache extends Module {
/**
* Т.к. название кеша может быть любым то предварительно хешируем имя кеша
*/
$sName=md5(SYS_CACHE_PREFIX.$sName);
if ($this->sCacheType==SYS_CACHE_TYPE_FILE) {
return unserialize($this->oBackendCache->load($sName));
if (!is_array($sName)) {
$sName=md5(SYS_CACHE_PREFIX.$sName);
if ($this->sCacheType==SYS_CACHE_TYPE_FILE) {
return unserialize($this->oBackendCache->load($sName));
} else {
return $this->oBackendCache->load($sName);
}
} else {
return $this->oBackendCache->load($sName);
return $this->multiGet($sName);
}
}
/**
* псевдо поддержка мульти-запросов к кешу
*
* @param unknown_type $aName
* @return unknown
*/
public function multiGet($aName) {
$aData=array();
foreach ($aName as $key => $sName) {
if ((false !== ($data = $this->Get($sName)))) {
$aData[$sName]=$data;
}
}
if (count($aData)>0) {
return $aData;
}
return false;
}
/**
* Записать значение в кеш
*