diff options
-rw-r--r-- | config/config.sample.php | 14 | ||||
-rw-r--r-- | lib/private/memcache/factory.php | 4 | ||||
-rw-r--r-- | lib/private/memcache/redis.php | 94 | ||||
-rw-r--r-- | tests/lib/memcache/redis.php | 29 |
4 files changed, 139 insertions, 2 deletions
diff --git a/config/config.sample.php b/config/config.sample.php index 791ffa3df90..35e3f6ce5f1 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -749,9 +749,21 @@ $CONFIG = array( */ 'cipher' => 'AES-256-CFB', + +/** + * Connection details for redis to use for memory caching. + * Redis is only used if other memory cache options (xcache, apc, apcu) are + * not available. + */ +'redis' => array( + 'host' => 'localhost', // can also be a unix domain socket: '/tmp/redis.sock' + 'port' => 6379, + 'timeout' => 0.0 +), + /** * Server details for one or more memcached servers to use for memory caching. - * Memcache is only used if other memory cache options (xcache, apc, apcu) are + * Memcache is only used if other memory cache options (xcache, apc, apcu, redis) are * not available. */ 'memcached_servers' => array( diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index 8e47a8899fc..dba9e8a0e00 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -37,6 +37,8 @@ class Factory implements ICacheFactory { return new APCu($prefix); } elseif (APC::isAvailable()) { return new APC($prefix); + } elseif (Redis::isAvailable()) { + return new Redis($prefix); } elseif (Memcached::isAvailable()) { return new Memcached($prefix); } else { @@ -50,7 +52,7 @@ class Factory implements ICacheFactory { * @return bool */ public function isAvailable() { - return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); + return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Redis::isAvailable() || Memcached::isAvailable(); } /** diff --git a/lib/private/memcache/redis.php b/lib/private/memcache/redis.php new file mode 100644 index 00000000000..f21619887d0 --- /dev/null +++ b/lib/private/memcache/redis.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright (c) 2014 Jörn Friedrich Dreyer <jfd@butonic.de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Redis extends Cache { + + /** + * @var \Redis $cache + */ + private static $cache = null; + + public function __construct($prefix = '') { + parent::__construct($prefix); + if (is_null(self::$cache)) { + // TODO allow configuring a RedisArray, see https://github.com/nicolasff/phpredis/blob/master/arrays.markdown#redis-arrays + self::$cache = new \Redis(); + $config = \OC::$server->getSystemConfig()->getValue('redis', array()); + if (isset($config['host'])) { + $host = $config['host']; + } else { + $host = '127.0.0.1'; + } + if (isset($config['port'])) { + $port = $config['port']; + } else { + $port = 6379; + } + if (isset($config['timeout'])) { + $timeout = $config['timeout']; + } else { + $timeout = 0.0; // unlimited + } + self::$cache->connect( $host, $port, $timeout ); + } + } + + /** + * entries in redis get namespaced to prevent collisions between ownCloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = self::$cache->get($this->getNamespace() . $key); + if ($result === false and ! self::$cache->exists($this->getNamespace() . $key)) { + return null; + } else { + return $result; + } + } + + public function set($key, $value, $ttl = 0) { + if ($ttl > 0) { + return self::$cache->setex($this->getNamespace() . $key, $ttl, $value); + } else { + return self::$cache->set($this->getNamespace() . $key, $value); + } + } + + public function hasKey($key) { + return self::$cache->exists($this->getNamespace() . $key); + } + + public function remove($key) { + if (self::$cache->delete($this->getNamespace() . $key)) { + return true; + } else { + return false; + } + + } + + public function clear($prefix = '') { + $prefix = $this->getNamespace() . $prefix.'*'; + $it = null; + self::$cache->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + while($keys = self::$cache->scan($it, $prefix)) { + self::$cache->delete($keys); + } + return true; + } + + static public function isAvailable() { + return extension_loaded('redis'); + } +} + diff --git a/tests/lib/memcache/redis.php b/tests/lib/memcache/redis.php new file mode 100644 index 00000000000..c0bd18b46f9 --- /dev/null +++ b/tests/lib/memcache/redis.php @@ -0,0 +1,29 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Memcache; + +class Redis extends Cache { + static public function setUpBeforeClass() { + parent::setUpBeforeClass(); + + if (!\OC\Memcache\Redis::isAvailable()) { + self::markTestSkipped('The redis extension is not available.'); + } + $instance = new \OC\Memcache\Redis(self::getUniqueID()); + if ($instance->set(self::getUniqueID(), self::getUniqueID()) === false) { + self::markTestSkipped('redis server seems to be down.'); + } + } + + protected function setUp() { + parent::setUp(); + $this->instance = new \OC\Memcache\Redis($this->getUniqueID()); + } +} |