diff --git a/lib/cache.php b/lib/cache.php index bc74ed83f8..48b9964ba9 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -15,41 +15,14 @@ class OC_Cache { * @var OC_Cache $global_cache */ static protected $global_cache; - /** - * @var OC_Cache $global_cache_fast - */ - static protected $global_cache_fast; - /** - * @var OC_Cache $user_cache_fast - */ - static protected $user_cache_fast; - static protected $isFast=null; /** * get the global cache * @return OC_Cache */ - static public function getGlobalCache($fast=false) { + static public function getGlobalCache() { if (!self::$global_cache) { - self::$global_cache_fast = null; - if (!self::$global_cache_fast && function_exists('xcache_set')) { - self::$global_cache_fast = new OC_Cache_XCache(true); - } - if (!self::$global_cache_fast && function_exists('apc_store')) { - self::$global_cache_fast = new OC_Cache_APC(true); - } - self::$global_cache = new OC_Cache_FileGlobal(); - if (self::$global_cache_fast) { - self::$global_cache = new OC_Cache_Broker(self::$global_cache_fast, self::$global_cache); - } - } - if($fast) { - if(self::$global_cache_fast) { - return self::$global_cache_fast; - }else{ - return false; - } } return self::$global_cache; } @@ -58,34 +31,16 @@ class OC_Cache { * get the user cache * @return OC_Cache */ - static public function getUserCache($fast=false) { + static public function getUserCache() { if (!self::$user_cache) { - self::$user_cache_fast = null; - if (!self::$user_cache_fast && function_exists('xcache_set')) { - self::$user_cache_fast = new OC_Cache_XCache(); - } - if (!self::$user_cache_fast && function_exists('apc_store')) { - self::$user_cache_fast = new OC_Cache_APC(); - } - self::$user_cache = new OC_Cache_File(); - if (self::$user_cache_fast) { - self::$user_cache = new OC_Cache_Broker(self::$user_cache_fast, self::$user_cache); - } - } - - if($fast) { - if(self::$user_cache_fast) { - return self::$user_cache_fast; - }else{ - return false; - } } return self::$user_cache; } /** * get a value from the user cache + * @param string $key * @return mixed */ static public function get($key) { @@ -95,6 +50,9 @@ class OC_Cache { /** * set a value in the user cache + * @param string $key + * @param mixed $value + * @param int $ttl * @return bool */ static public function set($key, $value, $ttl=0) { @@ -107,6 +65,7 @@ class OC_Cache { /** * check if a value is set in the user cache + * @param string $key * @return bool */ static public function hasKey($key) { @@ -116,6 +75,7 @@ class OC_Cache { /** * remove an item from the user cache + * @param string $key * @return bool */ static public function remove($key) { @@ -133,17 +93,6 @@ class OC_Cache { return $user_cache->clear($prefix); } - /** - * check if a fast memory based cache is available - * @return true - */ - static public function isFast() { - if(is_null(self::$isFast)) { - self::$isFast=function_exists('xcache_set') || function_exists('apc_store'); - } - return self::$isFast; - } - static public function generateCacheKeyFromFiles($files) { $key = ''; sort($files); diff --git a/lib/cache/apc.php b/lib/cache/apc.php deleted file mode 100644 index 895d307ea2..0000000000 --- a/lib/cache/apc.php +++ /dev/null @@ -1,64 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class OC_Cache_APC { - protected $prefix; - - public function __construct($global = false) { - $this->prefix = OC_Util::getInstanceId().'/'; - if (!$global) { - $this->prefix .= OC_User::getUser().'/'; - } - } - - /** - * entries in APC gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - - public function get($key) { - $result = apc_fetch($this->getNamespace().$key, $success); - if (!$success) { - return null; - } - return $result; - } - - public function set($key, $value, $ttl=0) { - return apc_store($this->getNamespace().$key, $value, $ttl); - } - - public function hasKey($key) { - return apc_exists($this->getNamespace().$key); - } - - public function remove($key) { - return apc_delete($this->getNamespace().$key); - } - - public function clear($prefix='') { - $ns = $this->getNamespace().$prefix; - $cache = apc_cache_info('user'); - foreach($cache['cache_list'] as $entry) { - if (strpos($entry['info'], $ns) === 0) { - apc_delete($entry['info']); - } - } - return true; - } -} -if(!function_exists('apc_exists')) { - function apc_exists($keys) - { - $result=false; - apc_fetch($keys, $result); - return $result; - } -} diff --git a/lib/memcache/apc.php b/lib/memcache/apc.php new file mode 100644 index 0000000000..575ee4427d --- /dev/null +++ b/lib/memcache/apc.php @@ -0,0 +1,67 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class APC extends Cache { + /** + * entries in APC gets namespaced to prevent collisions between owncloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = apc_fetch($this->getNamespace() . $key, $success); + if (!$success) { + return null; + } + return $result; + } + + public function set($key, $value, $ttl = 0) { + return apc_store($this->getNamespace() . $key, $value, $ttl); + } + + public function hasKey($key) { + return apc_exists($this->getNamespace() . $key); + } + + public function remove($key) { + return apc_delete($this->getNamespace() . $key); + } + + public function clear($prefix = '') { + $ns = $this->getNamespace() . $prefix; + $cache = apc_cache_info('user'); + foreach ($cache['cache_list'] as $entry) { + if (strpos($entry['info'], $ns) === 0) { + apc_delete($entry['info']); + } + } + return true; + } + + static public function isAvailable() { + if (!extension_loaded('apc')) { + return false; + } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + return false; + } else { + return true; + } + } +} + +if (!function_exists('apc_exists')) { + function apc_exists($keys) { + $result = false; + apc_fetch($keys, $result); + return $result; + } +} diff --git a/lib/memcache/cache.php b/lib/memcache/cache.php new file mode 100644 index 0000000000..0ad1cc7ec0 --- /dev/null +++ b/lib/memcache/cache.php @@ -0,0 +1,77 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +abstract class Cache implements \ArrayAccess { + /** + * @var string $prefix + */ + protected $prefix; + + /** + * @param string $prefix + */ + public function __construct($prefix = '') { + $this->prefix = \OC_Util::getInstanceId() . '/' . $prefix; + } + + public function getPrefix() { + return $this->prefix; + } + + /** + * @param string $key + * @return mixed + */ + abstract public function get($key); + + /** + * @param string $key + * @param mixed $value + * @param int $ttl + * @return mixed + */ + abstract public function set($key, $value, $ttl = 0); + + /** + * @param string $key + * @return mixed + */ + abstract public function hasKey($key); + + /** + * @param string $key + * @return mixed + */ + abstract public function remove($key); + + /** + * @param string $prefix + * @return mixed + */ + abstract public function clear($prefix = ''); + + //implement the ArrayAccess interface + + public function offsetExists($offset) { + return $this->hasKey($offset); + } + + public function offsetSet($offset, $value) { + $this->set($offset, $value); + } + + public function offsetGet($offset) { + return $this->get($offset); + } + + public function offsetUnset($offset) { + $this->remove($offset); + } +} diff --git a/lib/memcache/factory.php b/lib/memcache/factory.php new file mode 100644 index 0000000000..b1b4997103 --- /dev/null +++ b/lib/memcache/factory.php @@ -0,0 +1,38 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Factory { + /** + * get a cache instance, will return null if no backend is available + * + * @param string $prefix + * @return \OC\Memcache\Cache + */ + function create($prefix = '') { + if (XCache::isAvailable()) { + return new XCache($prefix); + } elseif (APC::isAvailable()) { + return new APC($prefix); + } elseif (Memcached::isAvailable()) { + return new Memcached($prefix); + } else { + return null; + } + } + + /** + * check if there is a memcache backend available + * + * @return bool + */ + public function isAvailable() { + return XCache::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); + } +} diff --git a/lib/memcache/memcached.php b/lib/memcache/memcached.php new file mode 100644 index 0000000000..978e6c2eff --- /dev/null +++ b/lib/memcache/memcached.php @@ -0,0 +1,76 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Memcached extends Cache { + /** + * @var \Memcached $cache + */ + private static $cache = null; + + public function __construct($prefix = '') { + parent::__construct($prefix); + if (is_null(self::$cache)) { + self::$cache = new \Memcached(); + list($host, $port) = \OC_Config::getValue('memcached_server', array('localhost', 11211)); + self::$cache->addServer($host, $port); + } + } + + /** + * entries in XCache gets 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->getResultCode() == \Memcached::RES_NOTFOUND) { + return null; + } else { + return $result; + } + } + + public function set($key, $value, $ttl = 0) { + if ($ttl > 0) { + return self::$cache->set($this->getNamespace() . $key, $value, $ttl); + } else { + return self::$cache->set($this->getNamespace() . $key, $value); + } + } + + public function hasKey($key) { + self::$cache->get($this->getNamespace() . $key); + return self::$cache->getResultCode() !== \Memcached::RES_NOTFOUND; + } + + public function remove($key) { + return self::$cache->delete($this->getNamespace() . $key); + } + + public function clear($prefix = '') { + $prefix = $this->getNamespace() . $prefix; + $allKeys = self::$cache->getAllKeys(); + $keys = array(); + $prefixLength = strlen($prefix); + foreach ($allKeys as $key) { + if (substr($key, 0, $prefixLength) === $prefix) { + $keys[] = $key; + } + } + self::$cache->deleteMulti($keys); + return true; + } + + static public function isAvailable() { + return extension_loaded('memcached'); + } +} diff --git a/lib/cache/xcache.php b/lib/memcache/xcache.php similarity index 69% rename from lib/cache/xcache.php rename to lib/memcache/xcache.php index 9f380f870b..33de30562f 100644 --- a/lib/cache/xcache.php +++ b/lib/memcache/xcache.php @@ -6,16 +6,9 @@ * See the COPYING-README file. */ -class OC_Cache_XCache { - protected $prefix; - - public function __construct($global = false) { - $this->prefix = OC_Util::getInstanceId().'/'; - if (!$global) { - $this->prefix .= OC_User::getUser().'/'; - } - } +namespace OC\Memcache; +class XCache extends Cache { /** * entries in XCache gets namespaced to prevent collisions between owncloud instances and users */ @@ -44,13 +37,24 @@ class OC_Cache_XCache { } public function clear($prefix='') { - if(!function_exists('xcache_unset_by_prefix')) { - function xcache_unset_by_prefix($prefix) { - // Since we can't clear targetted cache, we'll clear all. :( - xcache_clear_cache(XC_TYPE_VAR, 0); - } - } xcache_unset_by_prefix($this->getNamespace().$prefix); return true; } + + static public function isAvailable(){ + if (!extension_loaded('xcache')) { + return false; + } elseif (\OC::$CLI) { + return false; + }else{ + return true; + } + } +} + +if(!function_exists('xcache_unset_by_prefix')) { + function xcache_unset_by_prefix($prefix) { + // Since we can't clear targetted cache, we'll clear all. :( + xcache_clear_cache(\XC_TYPE_VAR, 0); + } } diff --git a/tests/lib/cache/apc.php b/tests/lib/cache/apc.php deleted file mode 100644 index bb5eb483db..0000000000 --- a/tests/lib/cache/apc.php +++ /dev/null @@ -1,35 +0,0 @@ -. -* -*/ - -class Test_Cache_APC extends Test_Cache { - public function setUp() { - if(!extension_loaded('apc')) { - $this->markTestSkipped('The apc extension is not available.'); - return; - } - if(!ini_get('apc.enable_cli') && OC::$CLI) { - $this->markTestSkipped('apc not available in CLI.'); - return; - } - $this->instance=new OC_Cache_APC(); - } -} diff --git a/tests/lib/cache/xcache.php b/tests/lib/cache/xcache.php deleted file mode 100644 index 43bed2db03..0000000000 --- a/tests/lib/cache/xcache.php +++ /dev/null @@ -1,31 +0,0 @@ -. -* -*/ - -class Test_Cache_XCache extends Test_Cache { - public function setUp() { - if(!function_exists('xcache_get')) { - $this->markTestSkipped('The xcache extension is not available.'); - return; - } - $this->instance=new OC_Cache_XCache(); - } -} diff --git a/tests/lib/memcache/apc.php b/tests/lib/memcache/apc.php new file mode 100644 index 0000000000..6b2a49470b --- /dev/null +++ b/tests/lib/memcache/apc.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Memcache; + +class APC extends Cache { + public function setUp() { + if(!\OC\Memcache\APC::isAvailable()) { + $this->markTestSkipped('The apc extension is not available.'); + return; + } + $this->instance=new \OC\Memcache\APC(uniqid()); + } +} diff --git a/tests/lib/memcache/cache.php b/tests/lib/memcache/cache.php new file mode 100644 index 0000000000..e2643b9fcd --- /dev/null +++ b/tests/lib/memcache/cache.php @@ -0,0 +1,58 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Memcache; + +class Cache extends \Test_Cache { + public function testExistsAfterSet() { + $this->assertFalse($this->instance->hasKey('foo')); + $this->instance->set('foo', 'bar'); + $this->assertTrue($this->instance->hasKey('foo')); + } + + public function testGetAfterSet() { + $this->assertNull($this->instance->get('foo')); + $this->instance->set('foo', 'bar'); + $this->assertEquals('bar', $this->instance->get('foo')); + } + + public function testDoesNotExistAfterRemove() { + $this->instance->set('foo', 'bar'); + $this->instance->remove('foo'); + $this->assertFalse($this->instance->hasKey('foo')); + } + + public function testArrayAccessSet() { + $this->instance['foo'] = 'bar'; + $this->assertEquals('bar', $this->instance->get('foo')); + } + + public function testArrayAccessGet() { + $this->instance->set('foo', 'bar'); + $this->assertEquals('bar', $this->instance['foo']); + } + + public function testArrayAccessExists() { + $this->assertFalse(isset($this->instance['foo'])); + $this->instance->set('foo', 'bar'); + $this->assertTrue(isset($this->instance['foo'])); + } + + public function testArrayAccessUnset() { + $this->instance->set('foo', 'bar'); + unset($this->instance['foo']); + $this->assertFalse($this->instance->hasKey('foo')); + } + + public function tearDown() { + if ($this->instance) { + $this->instance->clear(); + } + } +} diff --git a/tests/lib/memcache/memcached.php b/tests/lib/memcache/memcached.php new file mode 100644 index 0000000000..4b38ae8ef3 --- /dev/null +++ b/tests/lib/memcache/memcached.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Memcache; + +class Memcached extends Cache { + public function setUp() { + if (!\OC\Memcache\Memcached::isAvailable()) { + $this->markTestSkipped('The memcached extension is not available.'); + return; + } + $this->instance = new \OC\Memcache\Memcached(uniqid()); + } +} diff --git a/tests/lib/memcache/xcache.php b/tests/lib/memcache/xcache.php new file mode 100644 index 0000000000..f59afda396 --- /dev/null +++ b/tests/lib/memcache/xcache.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Memcache; + +class XCache extends Cache { + public function setUp() { + if (!\OC\Memcache\XCache::isAvailable()) { + $this->markTestSkipped('The xcache extension is not available.'); + return; + } + $this->instance = new \OC\Memcache\XCache(uniqid()); + } +}