@@ -24,7 +24,9 @@ | |||
namespace OC\Memcache; | |||
class APC extends Cache { | |||
use OCP\IMemcache; | |||
class APC extends Cache implements IMemcache { | |||
public function get($key) { | |||
$result = apc_fetch($this->getPrefix() . $key, $success); | |||
if (!$success) { | |||
@@ -52,6 +54,41 @@ class APC extends Cache { | |||
return apc_delete($iter); | |||
} | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
*/ | |||
public function add($key, $value, $ttl = 0) { | |||
return apc_add($this->getPrefix() . $key, $value, $ttl); | |||
} | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function inc($key, $step = 1) { | |||
$this->add($key, 0); | |||
return apc_inc($this->getPrefix() . $key, $step); | |||
} | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function dec($key, $step = 1) { | |||
return apc_dec($this->getPrefix() . $key, $step); | |||
} | |||
static public function isAvailable() { | |||
if (!extension_loaded('apc')) { | |||
return false; |
@@ -22,7 +22,9 @@ | |||
namespace OC\Memcache; | |||
class ArrayCache extends Cache { | |||
use OCP\IMemcache; | |||
class ArrayCache extends Cache implements IMemcache { | |||
/** @var array Array with the cached data */ | |||
protected $cachedData = array(); | |||
@@ -76,6 +78,58 @@ class ArrayCache extends Cache { | |||
return true; | |||
} | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
*/ | |||
public function add($key, $value, $ttl = 0) { | |||
// since this cache is not shared race conditions aren't an issue | |||
if ($this->hasKey($key)) { | |||
return false; | |||
} else { | |||
return $this->set($key, $value, $ttl); | |||
} | |||
} | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function inc($key, $step = 1) { | |||
$oldValue = $this->get($key); | |||
if (is_int($oldValue)) { | |||
$this->set($key, $oldValue + $step); | |||
return $oldValue + $step; | |||
} else { | |||
$success = $this->add($key, $step); | |||
return ($success) ? $step : false; | |||
} | |||
} | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function dec($key, $step = 1) { | |||
$oldValue = $this->get($key); | |||
if (is_int($oldValue)) { | |||
$this->set($key, $oldValue - $step); | |||
return $oldValue - $step; | |||
} else { | |||
return false; | |||
} | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ |
@@ -24,7 +24,9 @@ | |||
namespace OC\Memcache; | |||
class Memcached extends Cache { | |||
use OCP\IMemcache; | |||
class Memcached extends Cache implements IMemcache { | |||
/** | |||
* @var \Memcached $cache | |||
*/ | |||
@@ -100,6 +102,41 @@ class Memcached extends Cache { | |||
return true; | |||
} | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
*/ | |||
public function add($key, $value, $ttl = 0) { | |||
return self::$cache->add($this->getPrefix() . $key, $value, $ttl); | |||
} | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function inc($key, $step = 1) { | |||
$this->add($key, 0); | |||
return self::$cache->increment($this->getPrefix() . $key, $step); | |||
} | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function dec($key, $step = 1) { | |||
return self::$cache->decrement($this->getPrefix() . $key, $step); | |||
} | |||
static public function isAvailable() { | |||
return extension_loaded('memcached'); | |||
} |
@@ -23,7 +23,9 @@ | |||
namespace OC\Memcache; | |||
class Redis extends Cache { | |||
use OCP\IMemcache; | |||
class Redis extends Cache implements IMemcache { | |||
/** | |||
* @var \Redis $cache | |||
@@ -52,10 +54,10 @@ class Redis extends Cache { | |||
$timeout = 0.0; // unlimited | |||
} | |||
self::$cache->connect( $host, $port, $timeout ); | |||
self::$cache->connect($host, $port, $timeout); | |||
if (isset($config['dbindex'])) { | |||
self::$cache->select( $config['dbindex'] ); | |||
self::$cache->select($config['dbindex']); | |||
} | |||
} | |||
} | |||
@@ -94,19 +96,59 @@ class Redis extends Cache { | |||
} else { | |||
return false; | |||
} | |||
} | |||
public function clear($prefix = '') { | |||
$prefix = $this->getNamespace() . $prefix.'*'; | |||
$prefix = $this->getNamespace() . $prefix . '*'; | |||
$it = null; | |||
self::$cache->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); | |||
while($keys = self::$cache->scan($it, $prefix)) { | |||
while ($keys = self::$cache->scan($it, $prefix)) { | |||
self::$cache->delete($keys); | |||
} | |||
return true; | |||
} | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
*/ | |||
public function add($key, $value, $ttl = 0) { | |||
// dont encode ints for inc/dec | |||
if (!is_int($value)) { | |||
$value = json_encode($value); | |||
} | |||
return self::$cache->setnx($this->getPrefix() . $key, $value); | |||
} | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function inc($key, $step = 1) { | |||
return self::$cache->incrBy($this->getNamespace() . $key, $step); | |||
} | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function dec($key, $step = 1) { | |||
if (!$this->hasKey($key)) { | |||
return false; | |||
} | |||
return self::$cache->decrBy($this->getNamespace() . $key, $step); | |||
} | |||
static public function isAvailable() { | |||
return extension_loaded('redis'); | |||
} |
@@ -24,12 +24,13 @@ | |||
*/ | |||
namespace OC\Memcache; | |||
use OCP\IMemcache; | |||
/** | |||
* See http://xcache.lighttpd.net/wiki/XcacheApi for provided constants and | |||
* functions etc. | |||
*/ | |||
class XCache extends Cache { | |||
class XCache extends Cache implements IMemcache { | |||
/** | |||
* entries in XCache gets namespaced to prevent collisions between ownCloud instances and users | |||
*/ | |||
@@ -38,28 +39,28 @@ class XCache extends Cache { | |||
} | |||
public function get($key) { | |||
return xcache_get($this->getNamespace().$key); | |||
return xcache_get($this->getNamespace() . $key); | |||
} | |||
public function set($key, $value, $ttl=0) { | |||
if($ttl>0) { | |||
return xcache_set($this->getNamespace().$key, $value, $ttl); | |||
}else{ | |||
return xcache_set($this->getNamespace().$key, $value); | |||
public function set($key, $value, $ttl = 0) { | |||
if ($ttl > 0) { | |||
return xcache_set($this->getNamespace() . $key, $value, $ttl); | |||
} else { | |||
return xcache_set($this->getNamespace() . $key, $value); | |||
} | |||
} | |||
public function hasKey($key) { | |||
return xcache_isset($this->getNamespace().$key); | |||
return xcache_isset($this->getNamespace() . $key); | |||
} | |||
public function remove($key) { | |||
return xcache_unset($this->getNamespace().$key); | |||
return xcache_unset($this->getNamespace() . $key); | |||
} | |||
public function clear($prefix='') { | |||
public function clear($prefix = '') { | |||
if (function_exists('xcache_unset_by_prefix')) { | |||
return xcache_unset_by_prefix($this->getNamespace().$prefix); | |||
return xcache_unset_by_prefix($this->getNamespace() . $prefix); | |||
} else { | |||
// Since we can not clear by prefix, we just clear the whole cache. | |||
xcache_clear_cache(\XC_TYPE_VAR, 0); | |||
@@ -67,7 +68,46 @@ class XCache extends Cache { | |||
return true; | |||
} | |||
static public function isAvailable(){ | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
*/ | |||
public function add($key, $value, $ttl = 0) { | |||
if ($this->hasKey($key)) { | |||
return false; | |||
} else { | |||
return $this->set($key, $value, $ttl); | |||
} | |||
} | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function inc($key, $step = 1) { | |||
$this->add($key, 0); | |||
return xcache_inc($this->getPrefix() . $key, $step); | |||
} | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
*/ | |||
public function dec($key, $step = 1) { | |||
return xcache_dec($this->getPrefix() . $key, $step); | |||
} | |||
static public function isAvailable() { | |||
if (!extension_loaded('xcache')) { | |||
return false; | |||
} | |||
@@ -80,7 +120,7 @@ class XCache extends Cache { | |||
// AND administration functions are password-protected. | |||
return false; | |||
} | |||
$var_size = (int) ini_get('xcache.var_size'); | |||
$var_size = (int)ini_get('xcache.var_size'); | |||
if (!$var_size) { | |||
return false; | |||
} |
@@ -0,0 +1,68 @@ | |||
<?php | |||
/** | |||
* @author Robin Appelman <icewind@owncloud.com> | |||
* | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
/** | |||
* Public interface of ownCloud for apps to use. | |||
* Cache interface | |||
* | |||
*/ | |||
// use OCP namespace for all classes that are considered public. | |||
// This means that they should be used by apps instead of the internal ownCloud classes | |||
namespace OCP; | |||
/** | |||
* This interface defines method for accessing the file based user cache. | |||
* | |||
* @since 8.1.0 | |||
*/ | |||
interface IMemcache extends ICache { | |||
/** | |||
* Set a value in the cache if it's not already stored | |||
* | |||
* @param string $key | |||
* @param mixed $value | |||
* @param int $ttl Time To Live in seconds. Defaults to 60*60*24 | |||
* @return bool | |||
* @since 8.0.0 | |||
*/ | |||
public function add($key, $value, $ttl = 0); | |||
/** | |||
* Increase a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
* @since 8.0.0 | |||
*/ | |||
public function inc($key, $step = 1); | |||
/** | |||
* Decrease a stored number | |||
* | |||
* @param string $key | |||
* @param int $step | |||
* @return int | bool | |||
* @since 8.0.0 | |||
*/ | |||
public function dec($key, $step = 1); | |||
} |
@@ -10,6 +10,11 @@ | |||
namespace Test\Memcache; | |||
abstract class Cache extends \Test_Cache { | |||
/** | |||
* @var \OCP\IMemcache cache; | |||
*/ | |||
protected $instance; | |||
public function testExistsAfterSet() { | |||
$this->assertFalse($this->instance->hasKey('foo')); | |||
$this->instance->set('foo', 'bar'); | |||
@@ -56,6 +61,37 @@ abstract class Cache extends \Test_Cache { | |||
$this->assertFalse($this->instance->hasKey('foo')); | |||
} | |||
public function testAdd() { | |||
$this->assertTrue($this->instance->add('foo', 'bar')); | |||
$this->assertEquals('bar', $this->instance->get('foo')); | |||
$this->assertFalse($this->instance->add('foo', 'asd')); | |||
$this->assertEquals('bar', $this->instance->get('foo')); | |||
} | |||
public function testInc() { | |||
$this->assertEquals(1, $this->instance->inc('foo')); | |||
$this->assertEquals(1, $this->instance->get('foo')); | |||
$this->assertEquals(2, $this->instance->inc('foo')); | |||
$this->assertEquals(12, $this->instance->inc('foo', 10)); | |||
$this->instance->set('foo', 'bar'); | |||
$this->assertFalse($this->instance->inc('foo')); | |||
$this->assertEquals('bar', $this->instance->get('foo')); | |||
} | |||
public function testDec() { | |||
$this->assertEquals(false, $this->instance->dec('foo')); | |||
$this->instance->set('foo', 20); | |||
$this->assertEquals(19, $this->instance->dec('foo')); | |||
$this->assertEquals(19, $this->instance->get('foo')); | |||
$this->assertEquals(9, $this->instance->dec('foo', 10)); | |||
$this->instance->set('foo', 'bar'); | |||
$this->assertFalse($this->instance->dec('foo')); | |||
$this->assertEquals('bar', $this->instance->get('foo')); | |||
} | |||
protected function tearDown() { | |||
if ($this->instance) { | |||
$this->instance->clear(); |