[*] Classes: refactoring of cache classes

git-svn-id: http://dev.prestashop.com/svn/v1/branches/1.5.x@9191 b9a71923-0436-4b27-9f14-aed3839534dd
This commit is contained in:
rMalie
2011-10-10 14:45:27 +00:00
parent 31815febc5
commit ce914bd435
5 changed files with 512 additions and 321 deletions
+262 -39
View File
@@ -1,6 +1,6 @@
<?php
/*
* 2007-2011 PrestaShop
* 2007-2011 PrestaShop
*
* NOTICE OF LICENSE
*
@@ -27,54 +27,277 @@
abstract class CacheCore
{
/** @var Cache */
protected static $_instance;
protected $_keysCached = array();
protected $_tablesCached = array();
protected $_blackList = array('cart',
'cart_discount',
'cart_product',
'connections',
'connections_source',
'connections_page',
'customer',
'customer_group',
'customized_data',
'guest',
'pagenotfound',
'page_viewed');
/**
* Name of keys index
*/
const KEYS_NAME = '__keys__';
/**
* Name of SQL cache index
*/
const SQL_TABLES_NAME = 'tablesCached';
/**
* @var Cache
*/
protected static $instance;
/**
* @var array List all keys of cached data and their associated ttl
*/
protected $keys = array();
/**
* @var array Store list of tables and their associated keys for SQL cache (warning: this var must not be initialized here !)
*/
protected $sql_tables_cached;
/**
* @var array List of blacklisted tables for SQL cache, these tables won't be indexed
*/
protected $blacklist = array(
'cart',
'cart_discount',
'cart_product',
'connections',
'connections_source',
'connections_page',
'customer',
'customer_group',
'customized_data',
'guest',
'pagenotfound',
'page_viewed',
);
/**
* Cache a data
*
* @param string $key
* @param mixed $value
* @param int $ttl
* @return bool
*/
abstract protected function _set($key, $value, $ttl = 0);
/**
* Retrieve a cached data by key
*
* @param string $key
* @return mixed
*/
abstract protected function _get($key);
/**
* Check if a data is cached by key
*
* @param string $key
* @return bool
*/
abstract protected function _exists($key);
/**
* Delete a data from the cache by key
*
* @param string $key
* @return bool
*/
abstract protected function _delete($key);
/**
* Write keys index
*/
abstract protected function _writeKeys();
/**
* Clean all cached data
*/
abstract public function flush();
/**
* @return Cache
*/
public static function getInstance()
{
if(!isset(self::$_instance))
{
$caching_system = _PS_CACHING_SYSTEM_;
self::$_instance = new $caching_system();
}
return self::$_instance;
}
protected function __construct()
{
if (!self::$instance)
{
$caching_system = _PS_CACHING_SYSTEM_;
self::$instance = new $caching_system();
}
return self::$instance;
}
/**
* Store a data in cache
*
* @param string $key
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set($key, $value, $ttl = 0)
{
if ($this->_set($key, $value))
{
if ($ttl < 0)
$ttl = 0;
$this->keys[$key] = ($ttl == 0) ? 0 : time() + $ttl;
$this->_writeKeys();
return true;
}
return false;
}
/**
* Retrieve a data from cache
*
* @param string $key
* @return mixed
*/
public function get($key)
{
if (!isset($this->keys[$key]))
return false;
if ($this->keys[$key] > 0 && $this->keys[$key] < time())
{
$this->delete($key);
return false;
}
return $this->_get($key);
}
/**
* Check if a data is cached
*
* @param string $key
* @return bool
*/
public function exists($key)
{
if (!isset($this->keys[$key]))
return false;
if ($this->keys[$key] > 0 && $this->keys[$key] < time())
{
$this->delete($key);
return false;
}
return $this->_exists($key);
}
/**
* Delete one or several data from cache (* joker can be used)
* E.g.: delete('*'); delete('my_prefix_*'); delete('my_key_name');
*
* @param string $key
* @return array List of deleted keys
*/
public function delete($key)
{
$keys = array();
if ($key == '*')
$keys = $this->keys;
else if (strpos($key, '*') === false)
$keys = array($key);
else
{
$pattern = str_replace('\\*', '.*', preg_quote($key));
foreach ($this->keys as $k => $ttl)
if (preg_match('#^'.$pattern.'$#', $k))
$keys[] = $k;
}
d($keys);
if (!isset($this->keys[$key]))
return false;
if ($this->_delete($key))
{
unset($this->keys[$key]);
$this->_writeKeys();
return true;
}
return false;
}
/**
* Store a query in cache
*
* @param string $query
* @param array $result
*/
public function setQuery($query, $result)
{
if ($this->isBlacklist($query))
return true;
if (is_null($this->sql_tables_cached))
{
$this->sql_tables_cached = $this->get(self::SQL_TABLES_NAME);
if (!is_array($this->sql_tables_cached))
$this->sql_tables_cached = array();
}
// Store query results in cache if this query is not already cached
$key = md5($query);
if ($this->exists($key))
return true;
$this->set($key, $result);
// Get all table from the query and save them in cache
if (preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach($res[1] as $table)
if (!isset($this->sql_tables_cached[$table][$key]))
$this->sql_tables_cached[$table][$key] = true;
$this->set(self::SQL_TABLES_NAME, $this->sql_tables_cached);
}
/**
* Delete a query from cache
*
* @param string $query
*/
public function deleteQuery($query)
{
if (is_null($this->sql_tables_cached))
{
$this->sql_tables_cached = $this->get(self::SQL_TABLES_NAME);
if (!is_array($this->sql_tables_cached))
$this->sql_tables_cached = array();
}
if (preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach ($res[1] as $table)
if (isset($this->sql_tables_cached[$table]))
{
foreach (array_keys($this->sql_tables_cached[$table]) as $fs_key)
{
$this->delete($fs_key);
$this->delete($fs_key.'_nrows');
}
unset($this->sql_tables_cached[$table]);
}
$this->set(self::SQL_TABLES_NAME, $this->sql_tables_cached);
}
/**
* Check if a query contain blacklisted tables
*
* @param string $query
* @return bool
*/
protected function isBlacklist($query)
{
foreach ($this->_blackList AS $find)
foreach ($this->blacklist as $find)
if (strpos($query, $find))
return true;
return false;
}
abstract public function get($key);
abstract public function delete($key, $timeout = 0);
abstract public function set($key, $value, $expire = 0);
abstract public function flush();
abstract public function setQuery($query, $result);
abstract public function deleteQuery($query);
}
+74 -103
View File
@@ -25,144 +25,105 @@
* International Registered Trademark & Property of PrestaShop SA
*/
class CacheFsCore extends Cache {
class CacheFsCore extends Cache
{
/**
* @var int Number of subfolders to dispatch cached filenames
*/
protected $depth;
protected $_depth;
/**
* @var string Cache directory path
*/
protected $path;
protected function __construct()
{
parent::__construct();
$this->_init();
$this->depth = Db::getInstance()->getValue('SELECT value FROM '._DB_PREFIX_.'configuration WHERE name= \'PS_CACHEFS_DIRECTORY_DEPTH\'', false);
$this->path = _PS_CACHEFS_DIRECTORY_;
$keys_filename = $this->getFilename(self::KEYS_NAME);
if (file_exists($keys_filename))
$this->keys = unserialize(file_get_contents($keys_filename));
}
protected function _init()
/**
* @see Cache::_set()
*/
protected function _set($key, $value, $ttl = 0)
{
$this->_depth = Db::getInstance()->getValue('SELECT value FROM '._DB_PREFIX_.'configuration WHERE name=\'PS_CACHEFS_DIRECTORY_DEPTH\'', false);
return $this->_setKeys();
return (@file_put_contents($this->getFilename($key), serialize($value)));
}
public function set($key, $value, $expire = 0)
/**
* @see Cache::_get()
*/
protected function _get($key)
{
$path = $this->getPath();
for ($i = 0; $i < $this->_depth; $i++)
$path .= $key[$i].'/';
if (@file_put_contents($path.$key, serialize($value)))
$filename = $this->getFilename($key);
if (!file_exists($filename))
{
$this->_keysCached[$key] = true;
return $key;
}
return false;
}
public function setNumRows($key, $value, $expire = 0)
{
return $this->set($key.'_nrows', $value, $expire);
}
public function getNumRows($key)
{
return $this->get($key.'_nrows');
}
public function get($key)
{
if (!isset($this->_keysCached[$key]))
return false;
$path = $this->getPath();
for ($i = 0; $i < $this->_depth; $i++)
$path .= $key[$i].'/';
if (!file_exists($path.$key))
{
unset($this->_keysCached[$key]);
unset($this->keys[$key]);
$this->_writeKeys();
return false;
}
$file = file_get_contents($path.$key);
$file = file_get_contents($filename);
return unserialize($file);
}
protected function _setKeys()
/**
* @see Cache::_exists()
*/
protected function _exists($key)
{
if (file_exists($this->getPath().'keysCached'))
{
$file = file_get_contents($this->getPath().'keysCached');
$this->_keysCached = unserialize($file);
}
if (file_exists($this->getPath().'tablesCached'))
{
$file = file_get_contents($this->getPath().'tablesCached');
$this->_tablesCached = unserialize($file);
}
return true;
return file_exists($this->getFilename($key));
}
public function setQuery($query, $result)
/**
* @see Cache::_delete()
*/
protected function _delete($key)
{
$md5_query = md5($query);
if ($this->isBlacklist($query))
$filename = $this->getFilename($key);
if (!file_exists($filename))
return true;
$this->_setKeys();
if (isset($this->_keysCached[$md5_query]))
return true;
$key = $this->set($md5_query, $result);
if (preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach($res[1] AS $table)
if(!isset($this->_tablesCached[$table][$key]))
$this->_tablesCached[$table][$key] = true;
$this->_writeKeys();
return unlink($filename);
}
public function delete($key, $timeout = 0)
/**
* @see Cache::_writeKeys()
*/
protected function _writeKeys()
{
$path = $this->getPath();
if (!isset($this->_keysCached[$key]))
return;
for ($i = 0; $i < $this->_depth; $i++)
$path.=$key[$i].'/';
if (!file_exists($path.$key))
return true;
if (!unlink($path.$key))
return false;
unset($this->_keysCached[$key]);
return true;
}
public function deleteQuery($query)
{
$this->_setKeys();
if (preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach ($res[1] AS $table)
if (isset($this->_tablesCached[$table]))
{
foreach (array_keys($this->_tablesCached[$table]) AS $fsKey)
{
$this->delete($fsKey);
$this->delete($fsKey.'_nrows');
}
unset($this->_tablesCached[$table]);
}
$this->_writeKeys();
@file_put_contents($this->getFilename(self::KEYS_NAME), serialize($this->keys));
}
/**
* @see Cache::flush()
*/
public function flush()
{
$this->delete('*');
}
private function _writeKeys()
{
@file_put_contents($this->getPath().'keysCached', serialize($this->_keysCached));
@file_put_contents($this->getPath().'tablesCached', serialize($this->_tablesCached));
}
/**
* Delete cache directory
*/
public static function deleteCacheDirectory()
{
Tools::deleteDirectory($this->getPath(), false);
Tools::deleteDirectory($this->path, false);
}
/**
* Create cache directory
*
* @param int $level_depth
* @param string $directory
*/
public static function createCacheDirectories($level_depth, $directory = false)
{
if (!$directory)
$directory = $this->getPath();
$directory = $this->path;
$chars = '0123456789abcdefghijklmnopqrstuvwxyz';
for ($i = 0; $i < strlen($chars); $i++)
{
@@ -174,8 +135,18 @@ class CacheFsCore extends Cache {
}
}
protected function getPath()
/**
* Transform a key into its absolute path
*
* @param string $key
* @return string
*/
protected function getFilename($key)
{
return (defined('_PS_CACHEFS_DIRECTORY_') ? _PS_CACHEFS_DIRECTORY_ : dirname(__FILE__).'/../cache/cachefs/');
$path = $this->path;
for ($i = 0; $i < $this->depth; $i++)
$path .= $key[$i].'/';
return $path.$key;
}
}
+85 -88
View File
@@ -27,148 +27,145 @@
class CacheMemcacheCore extends Cache
{
protected $_memcacheObj;
protected $_isConnected = false;
/**
* @var Memcache
*/
protected $memcache;
protected function __construct()
/**
* @var bool Connection status
*/
protected $is_connected = false;
public function __construct()
{
parent::__construct();
$this->connect();
$this->keys = $this->memcache->get(self::KEYS_NAME);
}
public function __destruct()
{
$this->close();
}
/**
* Connect to memcache server
*/
public function connect()
{
$this->_memcacheObj = new Memcache();
$this->memcache = new Memcache();
$servers = self::getMemcachedServers();
if (!$servers)
return false;
foreach ($servers AS $server)
$this->_memcacheObj->addServer($server['ip'], $server['port'], $server['weight']);
$this->memcache->addServer($server['ip'], $server['port'], $server['weight']);
$this->_isConnected = true;
return $this->_setKeys();
$this->is_connected = true;
}
public function set($key, $value, $expire = 0)
/**
* @see Cache::_set()
*/
protected function _set($key, $value, $ttl = 0)
{
if (!$this->_isConnected)
if (!$this->is_connected)
return false;
if ($this->_memcacheObj->set($key, $value, 0, $expire))
{
$this->_keysCached[$key] = true;
return $key;
}
return $this->memcache->set($key, $value, 0, $ttl);
}
public function setNumRows($key, $value, $expire = 0)
/**
* @see Cache::_get()
*/
protected function _get($key)
{
return $this->set($key.'_nrows', $value, $expire);
}
public function getNumRows($key)
{
return $this->get($key.'_nrows');
}
public function get($key)
{
if (!isset($this->_keysCached[$key]))
if (!$this->is_connected)
return false;
return $this->_memcacheObj->get($key);
return $this->memcache->get($key);
}
protected function _setKeys()
/**
* @see Cache::_exists()
*/
protected function _exists($key)
{
if (!$this->_isConnected)
if (!$this->is_connected)
return false;
$this->_keysCached = $this->_memcacheObj->get('keysCached');
$this->_tablesCached = $this->_memcacheObj->get('tablesCached');
return true;
return isset($this->keys[$key]);
}
public function setQuery($query, $result)
/**
* @see Cache::_delete()
*/
protected function _delete($key)
{
if (!$this->_isConnected)
if (!$this->is_connected)
return false;
if ($this->isBlacklist($query))
return true;
$md5_query = md5($query);
$this->_setKeys();
if (isset($this->_keysCached[$md5_query]))
return true;
$key = $this->set($md5_query, $result);
if(preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach($res[1] AS $table)
if(!isset($this->_tablesCached[$table][$key]))
$this->_tablesCached[$table][$key] = true;
$this->_writeKeys();
return $this->memcache->delete($key);
}
public function delete($key, $timeout = 0)
/**
* @see Cache::_writeKeys()
*/
protected function _writeKeys()
{
if (!$this->_isConnected)
if (!$this->is_connected)
return false;
if (!empty($key) AND $this->_memcacheObj->delete($key, $timeout))
unset($this->_keysCached[$key]);
}
public function deleteQuery($query)
{
if (!$this->_isConnected)
return false;
$this->_setKeys();
if (preg_match_all('/('._DB_PREFIX_.'[a-z_-]*)`?.*/i', $query, $res))
foreach ($res[1] AS $table)
if (isset($this->_tablesCached[$table]))
{
foreach ($this->_tablesCached[$table] AS $memcachedKey => $foo)
{
$this->delete($memcachedKey);
$this->delete($memcachedKey.'_nrows');
}
unset($this->_tablesCached[$table]);
}
$this->_writeKeys();
}
protected function close()
{
if (!$this->_isConnected)
return false;
return $this->_memcacheObj->close();
$this->memcache->set(self::KEYS_NAME, $this->keys, 0, 0);
}
/**
* @see Cache::flush()
*/
public function flush()
{
if(!$this->_isConnected)
if(!$this->is_connected)
return false;
if ($this->_memcacheObj->flush())
if ($this->memcache->flush())
return $this->_setKeys();
return false;
}
private function _writeKeys()
/**
* Close connection to memcache server
*
* @return bool
*/
protected function close()
{
if (!$this->_isConnected)
if (!$this->is_connected)
return false;
$this->_memcacheObj->set('keysCached', $this->_keysCached, 0, 0);
$this->_memcacheObj->set('tablesCached', $this->_tablesCached, 0, 0);
$this->close();
return $this->memcache->close();
}
/**
* Add a memcache server
*
* @param string $ip
* @param int $port
* @param int $weight
*/
public static function addServer($ip, $port, $weight)
{
return Db::getInstance()->Execute('INSERT INTO '._DB_PREFIX_.'memcached_servers (ip, port, weight) VALUES(\''.pSQL($ip).'\', '.(int)$port.', '.(int)$weight.')', false);
return Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'memcached_servers (ip, port, weight) VALUES(\''.pSQL($ip).'\', '.(int)$port.', '.(int)$weight.')', false);
}
/**
* Get list of memcached servers
*
* @return array
*/
public static function getMemcachedServers()
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT * FROM '._DB_PREFIX_.'memcached_servers', true, false);
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM '._DB_PREFIX_.'memcached_servers', true, false);
}
/**
* Delete a memcache server
*
* @param int $id_server
*/
public static function deleteServer($id_server)
{
return Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'memcached_servers WHERE id_memcached_server='.(int)$id_server);
return Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'memcached_servers WHERE id_memcached_server='.(int)$id_server);
}
}