From 06235cd1568554fa508ece0f90dbdbda50ac4eec Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 24 Jun 2014 13:50:23 -0400 Subject: [PATCH] Fixes #2558: Enhanced support for memcached by adding `yii\caching\MemCache::persistentId` and `yii\caching\MemCache::options` --- framework/CHANGELOG.md | 1 + framework/caching/MemCache.php | 144 +++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 42 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 9ca41ee697..88bc6f8f14 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -59,6 +59,7 @@ Yii Framework 2 Change Log - Bug: Fixed Object of class Imagick could not be converted to string in CaptchaAction (eXprojects, cebe) - Enh #2264: `CookieCollection::has()` will return false for expired or removed cookies (qiangxue) - Enh #2435: `yii\db\IntegrityException` is now thrown on database integrity errors instead of general `yii\db\Exception` (samdark) +- Enh #2558: Enhanced support for memcached by adding `yii\caching\MemCache::persistentId` and `yii\caching\MemCache::options` (qiangxue) - Enh #2837: Error page now shows arguments in stack trace method calls (samdark) - Enh #2906: Added support for using conditional comments for js and css files registered through asset bundles and Html helper (exromany, qiangxue) - Enh #2942: Added truncate and truncateWord methods (Alex-Code, samdark) diff --git a/framework/caching/MemCache.php b/framework/caching/MemCache.php index 45256be7be..64deef8838 100644 --- a/framework/caching/MemCache.php +++ b/framework/caching/MemCache.php @@ -69,6 +69,19 @@ class MemCache extends Cache * Defaults to false. */ public $useMemcached = false; + /** + * @var string an ID that identifies a Memcached instance. This property is used only when [[useMemcached]] is true. + * By default the Memcached instances are destroyed at the end of the request. To create an instance that + * persists between requests, you may specify a unique ID for the instance. All instances created with the + * same ID will share the same connection. + * @see http://ca2.php.net/manual/en/memcached.construct.php + */ + public $persistentId; + /** + * @var array options for Memcached. This property is used only when [[useMemcached]] is true. + * @see http://ca2.php.net/manual/en/memcached.setoptions.php + */ + public $options; /** * @var \Memcache|\Memcached the Memcache instance */ @@ -86,50 +99,88 @@ class MemCache extends Cache public function init() { parent::init(); - $servers = $this->getServers(); - $cache = $this->getMemCache(); + $this->addServers($this->getMemcache(), $this->getServers()); + } + + /** + * @param \Memcache|\Memcached $cache + * @param array $servers + * @throws InvalidConfigException + */ + protected function addServers($cache, $servers) + { if (empty($servers)) { - $cache->addServer('127.0.0.1', 11211); + $servers = [new MemCacheServer([ + 'host' => '127.0.0.1', + 'port' => 11211, + ])]; } else { - if (!$this->useMemcached) { - // different version of memcache may have different number of parameters for the addServer method. - $class = new \ReflectionClass($cache); - $paramCount = $class->getMethod('addServer')->getNumberOfParameters(); - } foreach ($servers as $server) { if ($server->host === null) { throw new InvalidConfigException("The 'host' property must be specified for every memcache server."); } - if ($this->useMemcached) { - $cache->addServer($server->host, $server->port, $server->weight); - } else { - // $timeout is used for memcache versions that do not have timeoutms parameter - $timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0); - if ($paramCount === 9) { - $cache->addServer( - $server->host, - $server->port, - $server->persistent, - $server->weight, - $timeout, - $server->retryInterval, - $server->status, - $server->failureCallback, - $server->timeout - ); - } else { - $cache->addServer( - $server->host, - $server->port, - $server->persistent, - $server->weight, - $timeout, - $server->retryInterval, - $server->status, - $server->failureCallback - ); - } - } + } + } + if ($this->useMemcached) { + $this->addMemcachedServers($cache, $servers); + } else { + $this->addMemcacheServers($cache, $servers); + } + } + + /** + * @param \Memcached $cache + * @param array $servers + */ + protected function addMemcachedServers($cache, $servers) + { + $existingServers = []; + if ($this->persistentId !== null) { + foreach ($cache->getServerList() as $s) { + $existingServers[$s['host'] . ':' . $s['port']] = true; + } + } + foreach ($servers as $server) { + if (empty($existingServers) || !isset($existingServers[$server->host . ':' . $server->port])) { + $cache->addServer($server->host, $server->port, $server->weight); + } + } + } + + /** + * @param \Memcache $cache + * @param array $servers + */ + protected function addMemcacheServers($cache, $servers) + { + $class = new \ReflectionClass($cache); + $paramCount = $class->getMethod('addServer')->getNumberOfParameters(); + foreach ($servers as $server) { + // $timeout is used for memcache versions that do not have $timeoutms parameter + $timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0); + if ($paramCount === 9) { + $cache->addServer( + $server->host, + $server->port, + $server->persistent, + $server->weight, + $timeout, + $server->retryInterval, + $server->status, + $server->failureCallback, + $server->timeout + ); + } else { + $cache->addServer( + $server->host, + $server->port, + $server->persistent, + $server->weight, + $timeout, + $server->retryInterval, + $server->status, + $server->failureCallback + ); } } } @@ -146,14 +197,22 @@ class MemCache extends Cache if (!extension_loaded($extension)) { throw new InvalidConfigException("MemCache requires PHP $extension extension to be loaded."); } - $this->_cache = $this->useMemcached ? new \Memcached : new \Memcache; + + if ($this->useMemcached) { + $this->_cache = $this->persistentId !== null ? new \Memcached($this->persistentId) : new \Memcached; + if (!empty($this->options)) { + $this->_cache->setOptions($this->options); + } + } else { + $this->_cache = new \Memcache; + } } return $this->_cache; } /** - * Returns the memcache server configurations. + * Returns the memcache or memcached server configurations. * @return MemCacheServer[] list of memcache server configurations. */ public function getServers() @@ -162,9 +221,10 @@ class MemCache extends Cache } /** - * @param array $config list of memcache server configurations. Each element must be an array + * @param array $config list of memcache or memcached server configurations. Each element must be an array * with the following keys: host, port, persistent, weight, timeout, retryInterval, status. - * @see http://www.php.net/manual/en/function.Memcache-addServer.php + * @see http://php.net/manual/en/memcache.addserver.php + * @see http://php.net/manual/en/memcached.addserver.php */ public function setServers($config) {