1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-05-25 20:28:12 +03:00
ifhub.club/framework/classes/modules/cache/Cache.class.php
2013-08-08 18:00:37 +07:00

379 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
require_once(Config::Get('path.framework.libs_vendor.server').'/DklabCache/config.php');
require_once(LS_DKCACHE_PATH.'Zend/Cache.php');
require_once(LS_DKCACHE_PATH.'Cache/Backend/MemcachedMultiload.php');
require_once(LS_DKCACHE_PATH.'Cache/Backend/TagEmuWrapper.php');
require_once(LS_DKCACHE_PATH.'Cache/Backend/Profiler.php');
/**
* Типы кеширования: file и memory
*
*/
define('SYS_CACHE_TYPE_FILE','file');
define('SYS_CACHE_TYPE_MEMORY','memory');
define('SYS_CACHE_TYPE_XCACHE','xcache');
/**
* Модуль кеширования.
* Для реализации кеширования используетс библиотека Zend_Cache с бэкэндами File, Memcache и XCache.
* Т.к. в memcache нет встроенной поддержки тегирования при кешировании, то для реализации тегов используется враппер от Дмитрия Котерова - Dklab_Cache_Backend_TagEmuWrapper.
*
* Пример использования:
* <pre>
* // Получает пользователя по его логину
* public function GetUserByLogin($sLogin) {
* // Пытаемся получить значение из кеша
* if (false === ($oUser = $this->Cache_Get("user_login_{$sLogin}"))) {
* // Если значение из кеша получить не удалось, то обращаемся к базе данных
* $oUser = $this->oMapper->GetUserByLogin($sLogin);
* // Записываем значение в кеш
* $this->Cache_Set($oUser, "user_login_{$sLogin}", array(), 60*60*24*5);
* }
* return $oUser;
* }
*
* // Обновляет пользовател в БД
* public function UpdateUser($oUser) {
* // Удаляем кеш конкретного пользователя
* $this->Cache_Delete("user_login_{$oUser->getLogin()}");
* // Удалем кеш со списком всех пользователей
* $this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,array('user_update'));
* // Обновлем пользовател в базе данных
* return $this->oMapper->UpdateUser($oUser);
* }
*
* // Получает список всех пользователей
* public function GetUsers() {
* // Пытаемся получить значение из кеша
* if (false === ($aUserList = $this->Cache_Get("users"))) {
* // Если значение из кеша получить не удалось, то обращаемся к базе данных
* $aUserList = $this->oMapper->GetUsers();
* // Записываем значение в кеш
* $this->Cache_Set($aUserList, "users", array('user_update'), 60*60*24*5);
* }
* return $aUserList;
* }
* </pre>
*
* @package engine.modules
* @since 1.0
*/
class ModuleCache extends Module {
/**
* Объект бэкенда кеширования
*
* @var Zend_Cache_Backend
*/
protected $oBackendCache=null;
/**
* Используется кеширование или нет
*
* @var bool
*/
protected $bUseCache;
/**
* Тип кеширования, прописан в глобльном конфиге config.php
*
* @var string
*/
protected $sCacheType;
/**
* Статистика кеширования
*
* @var array
*/
protected $aStats=array(
'time' =>0,
'count' => 0,
'count_get' => 0,
'count_set' => 0,
);
/**
* Хранилище для кеша на время сессии
* @see SetLife
* @see GetLife
*
* @var array
*/
protected $aStoreLife=array();
/**
* Префикс для "умного" кеширования
* @see SmartSet
* @see SmartGet
*
* @var string
*/
protected $sPrefixSmartCache='for-smart-cache-';
/**
* Инициализируем нужный тип кеша
*
*/
public function Init() {
$this->bUseCache=Config::Get('sys.cache.use');
$this->sCacheType=Config::Get('sys.cache.type');
if (!$this->bUseCache) {
return false;
}
/**
* Файловый кеш
*/
if ($this->sCacheType==SYS_CACHE_TYPE_FILE) {
require_once(LS_DKCACHE_PATH.'Zend/Cache/Backend/File.php');
$sDirCache=Config::Get('sys.cache.dir').'/system/';
if (!is_dir($sDirCache)) @mkdir($sDirCache,0777,true);
$oCahe = new Zend_Cache_Backend_File(
array(
'cache_dir' => $sDirCache,
'file_name_prefix' => Config::Get('sys.cache.prefix'),
'read_control_type' => 'crc32',
'hashed_directory_level' => Config::Get('sys.cache.directory_level'),
'read_control' => true,
'file_locking' => true,
)
);
$this->oBackendCache = new Dklab_Cache_Backend_Profiler($oCahe,array($this,'CalcStats'));
/**
* Кеш на основе Memcached
*/
} elseif ($this->sCacheType==SYS_CACHE_TYPE_MEMORY) {
require_once(LS_DKCACHE_PATH.'Zend/Cache/Backend/Memcached.php');
$aConfigMem=Config::Get('memcache');
$oCahe = new Dklab_Cache_Backend_MemcachedMultiload($aConfigMem);
$this->oBackendCache = new Dklab_Cache_Backend_TagEmuWrapper(new Dklab_Cache_Backend_Profiler($oCahe,array($this,'CalcStats')));
/**
* Кеш на основе XCache
*/
} elseif ($this->sCacheType==SYS_CACHE_TYPE_XCACHE) {
require_once(LS_DKCACHE_PATH.'Zend/Cache/Backend/Xcache.php');
$aConfigMem=Config::Get('xcache');
$oCahe = new Zend_Cache_Backend_Xcache(is_array($aConfigMem) ? $aConfigMem : array());
$this->oBackendCache = new Dklab_Cache_Backend_TagEmuWrapper(new Dklab_Cache_Backend_Profiler($oCahe,array($this,'CalcStats')));
} else {
throw new Exception("Wrong type of caching: ".$this->sCacheType." (file, memory, xcache)");
}
/**
* Дабы не засорять место протухшим кешем, удаляем его в случайном порядке, например 1 из 50 раз
*/
if (rand(1,50)==33) {
$this->Clean(Zend_Cache::CLEANING_MODE_OLD);
}
}
/**
* Получить значение из кеша
*
* @param string $sName Имя ключа
* @return mixed|bool
*/
public function Get($sName) {
if (!$this->bUseCache) {
return false;
}
/**
* Т.к. название кеша может быть любым то предварительно хешируем имя кеша
*/
if (!is_array($sName)) {
$sName=md5(Config::Get('sys.cache.prefix').$sName);
$data=$this->oBackendCache->load($sName);
if ($this->sCacheType==SYS_CACHE_TYPE_FILE and $data!==false) {
return unserialize($data);
} else {
return $data;
}
} else {
return $this->multiGet($sName);
}
}
/**
* Получения значения из "умного" кеша для борьбы с конкурирующими запросами
* Если кеш "протух", и за ним обращаются много запросов, то только первый запрос вернет FALSE, остальные будут получать чуть устаревшие данные из временного кеша, пока их не обновит первый запрос
*
* @param $sName Имя ключа
* @return bool|mixed
*/
public function SmartGet($sName) {
if (!$this->bUseCache) {
return false;
}
/**
* Если данных в основном кеше нет, то перекладываем их из временного
*/
if (($data=$this->Get($sName))===false) {
$this->Set($this->Get($this->sPrefixSmartCache.$sName),$sName,array(),60); // храним данные из временного в основном не долго
}
return $data;
}
/**
* Поддержка мульти-запросов к кешу
* Такие запросы поддерживает только memcached, поэтому для остальных типов делаем эмуляцию
*
* @param array $aName Имя ключа
* @return bool|array
*/
public function multiGet($aName) {
if (count($aName)==0) {
return false;
}
if ($this->sCacheType==SYS_CACHE_TYPE_MEMORY) {
$aKeys=array();
$aKv=array();
foreach ($aName as $sName) {
$aKeys[]=md5(Config::Get('sys.cache.prefix').$sName);
$aKv[md5(Config::Get('sys.cache.prefix').$sName)]=$sName;
}
$data=$this->oBackendCache->load($aKeys);
if ($data and is_array($data)) {
$aData=array();
foreach ($data as $key => $value) {
$aData[$aKv[$key]]=$value;
}
if (count($aData)>0) {
return $aData;
}
}
return false;
} else {
$aData=array();
foreach ($aName as $key => $sName) {
if ((false !== ($data = $this->Get($sName)))) {
$aData[$sName]=$data;
}
}
if (count($aData)>0) {
return $aData;
}
return false;
}
}
/**
* Записать значение в кеш
*
* @param mixed $data Данные для хранения в кеше
* @param string $sName Имя ключа
* @param array $aTags Список тегов, для возможности удалять сразу несколько кешей по тегу
* @param int $iTimeLife Время жизни кеша в секундах
* @return bool
*/
public function Set($data,$sName,$aTags=array(),$iTimeLife=false) {
if (!$this->bUseCache) {
return false;
}
/**
* Т.к. название кеша может быть любым то предварительно хешируем имя кеша
*/
$sName=md5(Config::Get('sys.cache.prefix').$sName);
if ($this->sCacheType==SYS_CACHE_TYPE_FILE) {
$data=serialize($data);
}
return $this->oBackendCache->save($data,$sName,$aTags,$iTimeLife);
}
/**
* Устанавливаем значение в "умном" кеша для борьбы с конкурирующими запросами
* Дополнительно сохраняет значение во временном кеше на чуть большее время
*
* @param mixed $data Данные для хранения в кеше
* @param string $sName Имя ключа
* @param array $aTags Список тегов, для возможности удалять сразу несколько кешей по тегу
* @param int $iTimeLife Время жизни кеша в секундах
* @return bool
*/
public function SmartSet($data,$sName,$aTags=array(),$iTimeLife=false) {
$this->Set($data,$this->sPrefixSmartCache.$sName,array(),$iTimeLife!==false ? $iTimeLife+60 : false);
return $this->Set($data,$sName,$aTags,$iTimeLife);
}
/**
* Удаляет значение из кеша по ключу(имени)
*
* @param string $sName Имя ключа
* @return bool
*/
public function Delete($sName) {
if (!$this->bUseCache) {
return false;
}
/**
* Т.к. название кеша может быть любым то предварительно хешируем имя кеша
*/
$sName=md5(Config::Get('sys.cache.prefix').$sName);
return $this->oBackendCache->remove($sName);
}
/**
* Чистит кеши
*
* @param int $cMode Режим очистки кеша
* @param array $aTags Список тегов, актуально для режима Zend_Cache::CLEANING_MODE_MATCHING_TAG
* @return bool
*/
public function Clean($cMode = Zend_Cache::CLEANING_MODE_ALL, $aTags = array()) {
if (!$this->bUseCache) {
return false;
}
return $this->oBackendCache->clean($cMode,$aTags);
}
/**
* Подсчет статистики использования кеша
*
* @param int $iTime Время выполнения метода
* @param string $sMethod имя метода
*/
public function CalcStats($iTime,$sMethod) {
$this->aStats['time']+=$iTime;
$this->aStats['count']++;
if ($sMethod=='Dklab_Cache_Backend_Profiler::load') {
$this->aStats['count_get']++;
}
if ($sMethod=='Dklab_Cache_Backend_Profiler::save') {
$this->aStats['count_set']++;
}
}
/**
* Возвращает статистику использования кеша
*
* @return array
*/
public function GetStats() {
return $this->aStats;
}
/**
* Сохраняет значение в кеше на время исполнения скрипта(сессии), некий аналог Registry
*
* @param mixed $data Данные для сохранения в кеше
* @param string $sName Имя ключа
*/
public function SetLife($data,$sName) {
$this->aStoreLife[$sName]=$data;
}
/**
* Получает значение из текущего кеша сессии
*
* @param string $sName Имя ключа
* @return mixed
*/
public function GetLife($sName) {
if (array_key_exists($sName,$this->aStoreLife)) {
return $this->aStoreLife[$sName];
}
return false;
}
}
?>