Caches divided up into two groups: distributed and local. 'Low latency' is an alias for local caches, while the standard `create()` call tries to get distributed caches first, then local caches. Memcache backend is set in `config.php`, with the keys `memcache.local` and `memcache.distributed`. If not set, `memcache.distributed` defaults to the value of `memcache.local`.tags/v8.1.0alpha1
@@ -782,10 +782,33 @@ $CONFIG = array( | |||
'cipher' => 'AES-256-CFB', | |||
/** | |||
* Memory caching backend configuration | |||
* | |||
* Available cache backends: | |||
* - \OC\Memcache\APC Alternative PHP Cache backend | |||
* - \OC\Memcache\APCu APC user backend | |||
* - \OC\Memcache\ArrayCache In-memory array-based backend (not recommended) | |||
* - \OC\Memcache\Memcached Memcached backend | |||
* - \OC\Memcache\Redis Redis backend | |||
* - \OC\Memcache\XCache XCache backend | |||
*/ | |||
/** | |||
* Memory caching backend for locally stored data | |||
* Used for host-specific data, e.g. file paths | |||
*/ | |||
'memcache.local' => '\OC\Memcache\APCu', | |||
/** | |||
* Memory caching backend for distributed data | |||
* Used for installation-specific data, e.g. database caching | |||
* If unset, defaults to the value of memcache.local | |||
*/ | |||
'memcache.distributed' => '\OC\Memcache\Memcached', | |||
/** | |||
* 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' | |||
@@ -795,8 +818,6 @@ $CONFIG = array( | |||
/** | |||
* 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, | |||
* redis) are not available. | |||
*/ | |||
'memcached_servers' => array( | |||
// hostname, port and optional weight. Also see: | |||
@@ -806,6 +827,7 @@ $CONFIG = array( | |||
//array('other.host.local', 11211), | |||
), | |||
/** | |||
* Location of the cache folder, defaults to ``data/$user/cache`` where | |||
* ``$user`` is the current user. When specified, the format will change to |
@@ -726,8 +726,8 @@ class OC { | |||
$instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null); | |||
if ($instanceId) { | |||
try { | |||
$memcacheFactory = new \OC\Memcache\Factory($instanceId); | |||
self::$loader->setMemoryCache($memcacheFactory->createLowLatency('Autoloader')); | |||
$memcacheFactory = \OC::$server->getMemCacheFactory(); | |||
self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader')); | |||
} catch (\Exception $ex) { | |||
} | |||
} |
@@ -11,77 +11,96 @@ namespace OC\Memcache; | |||
use \OCP\ICacheFactory; | |||
class Factory implements ICacheFactory { | |||
const NULL_CACHE = '\\OC\\Memcache\\Null'; | |||
/** | |||
* @var string $globalPrefix | |||
*/ | |||
private $globalPrefix; | |||
/** | |||
* @var string $localCacheClass | |||
*/ | |||
private $localCacheClass; | |||
/** | |||
* @var string $distributedCacheClass | |||
*/ | |||
private $distributedCacheClass; | |||
/** | |||
* @param string $globalPrefix | |||
* @param string|null $localCacheClass | |||
* @param string|null $distributedCacheClass | |||
*/ | |||
public function __construct($globalPrefix) { | |||
public function __construct($globalPrefix, | |||
$localCacheClass = null, $distributedCacheClass = null) | |||
{ | |||
$this->globalPrefix = $globalPrefix; | |||
if (!($localCacheClass && $localCacheClass::isAvailable())) { | |||
$localCacheClass = self::NULL_CACHE; | |||
} | |||
if (!($distributedCacheClass && $distributedCacheClass::isAvailable())) { | |||
$distributedCacheClass = $localCacheClass; | |||
} | |||
$this->localCacheClass = $localCacheClass; | |||
$this->distributedCacheClass = $distributedCacheClass; | |||
} | |||
/** | |||
* get a cache instance, or Null backend if no backend available | |||
* create a distributed cache instance | |||
* | |||
* @param string $prefix | |||
* @return \OC\Memcache\Cache | |||
*/ | |||
function create($prefix = '') { | |||
$prefix = $this->globalPrefix . '/' . $prefix; | |||
if (XCache::isAvailable()) { | |||
return new XCache($prefix); | |||
} elseif (APCu::isAvailable()) { | |||
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 { | |||
return new ArrayCache($prefix); | |||
} | |||
public function createDistributed($prefix = '') { | |||
return new $this->distributedCacheClass($this->globalPrefix . '/' . $prefix); | |||
} | |||
/** | |||
* create a local cache instance | |||
* | |||
* @param string $prefix | |||
* @return \OC\Memcache\Cache | |||
*/ | |||
public function createLocal($prefix = '') { | |||
return new $this->localCacheClass($this->globalPrefix . '/' . $prefix); | |||
} | |||
/** | |||
* @see \OC\Memcache\Factory::createDistributed() | |||
* @param string $prefix | |||
* @return \OC\Memcache\Cache | |||
*/ | |||
public function create($prefix = '') { | |||
return $this->createDistributed($prefix); | |||
} | |||
/** | |||
* check if there is a memcache backend available | |||
* check memcache availability | |||
* | |||
* @return bool | |||
*/ | |||
public function isAvailable() { | |||
return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Redis::isAvailable() || Memcached::isAvailable(); | |||
return ($this->distributedCacheClass !== self::NULL_CACHE); | |||
} | |||
/** | |||
* get a in-server cache instance, will return null if no backend is available | |||
* | |||
* @see \OC\Memcache\Factory::createLocal() | |||
* @param string $prefix | |||
* @return null|Cache | |||
* @return \OC\Memcache\Cache|null | |||
*/ | |||
public function createLowLatency($prefix = '') { | |||
$prefix = $this->globalPrefix . '/' . $prefix; | |||
if (XCache::isAvailable()) { | |||
return new XCache($prefix); | |||
} elseif (APCu::isAvailable()) { | |||
return new APCu($prefix); | |||
} elseif (APC::isAvailable()) { | |||
return new APC($prefix); | |||
} else { | |||
return null; | |||
} | |||
return $this->createLocal($prefix); | |||
} | |||
/** | |||
* check if there is a in-server backend available | |||
* check local memcache availability | |||
* | |||
* @return bool | |||
*/ | |||
public function isAvailableLowLatency() { | |||
return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable(); | |||
return ($this->localCacheClass !== self::NULL_CACHE); | |||
} | |||
} |
@@ -155,8 +155,12 @@ class Server extends SimpleContainer implements IServerContainer { | |||
return new UserCache(); | |||
}); | |||
$this->registerService('MemCacheFactory', function ($c) { | |||
$config = $c->getConfig(); | |||
$instanceId = \OC_Util::getInstanceId(); | |||
return new \OC\Memcache\Factory($instanceId); | |||
return new \OC\Memcache\Factory($instanceId, | |||
$config->getSystemValue('memcache.local', null), | |||
$config->getSystemValue('memcache.distributed', null) | |||
); | |||
}); | |||
$this->registerService('ActivityManager', function ($c) { | |||
return new ActivityManager(); |
@@ -0,0 +1,110 @@ | |||
<?php | |||
/** | |||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk> | |||
* | |||
* @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/> | |||
* | |||
*/ | |||
namespace Test\Memcache; | |||
class Test_Factory_Available_Cache1 { | |||
public function __construct($prefix = '') { | |||
} | |||
public static function isAvailable() { | |||
return true; | |||
} | |||
} | |||
class Test_Factory_Available_Cache2 { | |||
public function __construct($prefix = '') { | |||
} | |||
public static function isAvailable() { | |||
return true; | |||
} | |||
} | |||
class Test_Factory_Unavailable_Cache1 { | |||
public function __construct($prefix = '') { | |||
} | |||
public static function isAvailable() { | |||
return false; | |||
} | |||
} | |||
class Test_Factory_Unavailable_Cache2 { | |||
public function __construct($prefix = '') { | |||
} | |||
public static function isAvailable() { | |||
return false; | |||
} | |||
} | |||
class Test_Factory extends \Test\TestCase { | |||
const AVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Available_Cache1'; | |||
const AVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Available_Cache2'; | |||
const UNAVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache1'; | |||
const UNAVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache2'; | |||
public function cacheAvailabilityProvider() { | |||
return [ | |||
[ | |||
// local and distributed available | |||
self::AVAILABLE1, self::AVAILABLE2, | |||
self::AVAILABLE1, self::AVAILABLE2 | |||
], | |||
[ | |||
// local available, distributed unavailable | |||
self::AVAILABLE1, self::UNAVAILABLE1, | |||
self::AVAILABLE1, self::AVAILABLE1 | |||
], | |||
[ | |||
// local unavailable, distributed available | |||
self::UNAVAILABLE1, self::AVAILABLE1, | |||
\OC\Memcache\Factory::NULL_CACHE, self::AVAILABLE1 | |||
], | |||
[ | |||
// local and distributed unavailable | |||
self::UNAVAILABLE1, self::UNAVAILABLE2, | |||
\OC\Memcache\Factory::NULL_CACHE, \OC\Memcache\Factory::NULL_CACHE | |||
], | |||
[ | |||
// local and distributed null | |||
null, null, | |||
\OC\Memcache\Factory::NULL_CACHE, \OC\Memcache\Factory::NULL_CACHE | |||
], | |||
[ | |||
// local available, distributed null (most common scenario) | |||
self::AVAILABLE1, null, | |||
self::AVAILABLE1, self::AVAILABLE1 | |||
] | |||
]; | |||
} | |||
/** | |||
* @dataProvider cacheAvailabilityProvider | |||
*/ | |||
public function testCacheAvailability($localCache, $distributedCache, | |||
$expectedLocalCache, $expectedDistributedCache) | |||
{ | |||
$factory = new \OC\Memcache\Factory('abc', $localCache, $distributedCache); | |||
$this->assertTrue(is_a($factory->createLocal(), $expectedLocalCache)); | |||
$this->assertTrue(is_a($factory->createDistributed(), $expectedDistributedCache)); | |||
} | |||
} |