Merge branch 'feature/add_redis_as_cache' of https://github.com/ledgr/roundcubemail into ledgr-feature/add_redis_as_cache

pull/5742/merge
Aleksander Machniak 7 years ago
commit fa06d37901

@ -66,6 +66,13 @@ class rcube
*/
public $memcache;
/**
* Instance of Redis class.
*
* @var Redis
*/
public $redis;
/**
* Instance of rcube_session class.
*
@ -268,11 +275,149 @@ class rcube
}
}
/**
* Get global handle for redis access
*
* @return object Redis
*/
public function get_redis()
{
if (!isset($this->redis)) {
if (!class_exists('Redis')) {
$this->redis = false;
rcube::raise_error(
array(
'code' => 604,
'type' => 'redis',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Failed to find Redis. Make sure php-redis is included"
),
true,
true
);
}
$this->redis = new Redis;
$this->redis_init();
if (!$this->redis_available) {
$this->redis = false;
}
}
return $this->redis;
}
/**
* Get global handle for redis access
*/
protected function redis_init()
{
$this->redis_available = false;
$hosts = $this->config->get('redis_hosts');
// host config is wrong
if (!is_array($hosts) || empty($hosts)) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'redis',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Redis host not configured"
),
true,
true
);
}
// only allow 1 host for now until we support clustering
if (count($hosts) > 1) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'redis',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Redis cluster not yet supported"
),
true,
true
);
}
foreach ($hosts as $redis_host) {
// explode individual fields
list($host, $port, $database, $password) = array_pad(explode(':', $redis_host, 4), 4, null);
$params = parse_url($redis_host);
if ($params['scheme'] == 'redis') {
$host = (isset($params['host'])) ? $params['host'] : null;
$port = (isset($params['port'])) ? $params['port'] : null;
$database = (isset($params['database'])) ? $params['database'] : null;
$password = (isset($params['password'])) ? $params['password'] : null;
}
// set default values if not set
$host = ($host !== null) ? $host : '127.0.0.1';
$port = ($port !== null) ? $port : 6379;
$database = ($database !== null) ? $database : 0;
if ($this->redis->connect($host, $port) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not connect to Redis server. Please check host and port"
),
true,
true
);
}
if ($password != null && $this->redis->auth($password) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not authenticate with Redis server. Please check password."
),
true,
true
);
}
if ($database != 0 && $this->redis->select($database) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not select Redis database. Please check database setting."
),
true,
true
);
}
}
if ($this->redis->ping() == "+PONG") {
$this->redis_available = true;
}
}
/**
* Initialize and get cache object
*
* @param string $name Cache identifier
* @param string $type Cache type ('db', 'apc' or 'memcache')
* @param string $type Cache type ('db', 'apc', 'memcache', 'redis')
* @param string $ttl Expiration time for cache items
* @param bool $packed Enables/disables data serialization
*
@ -1044,7 +1189,7 @@ class rcube
/**
* When you're going to sleep the script execution for a longer time
* it is good to close all external connections (sql, memcache, SMTP, IMAP).
* it is good to close all external connections (sql, memcache, redis, SMTP, IMAP).
*
* No action is required on wake up, all connections will be
* re-established automatically.
@ -1074,6 +1219,10 @@ class rcube
if ($this->smtp) {
$this->smtp->disconnect();
}
if ($this->redis) {
$this->redis->close();
}
}
/**
@ -1396,7 +1545,7 @@ class rcube
/**
* Write debug info to the log
*
* @param string $engine Engine type - file name (memcache, apc)
* @param string $engine Engine type - file name (memcache, apc, redis)
* @param string $data Data string to log
* @param bool $result Operation result
*/

@ -31,7 +31,7 @@ class rcube_cache
/**
* Instance of database handler
*
* @var rcube_db|Memcache|bool
* @var rcube_db|Memcache|Redis|bool
*/
private $db;
private $type;
@ -52,7 +52,7 @@ class rcube_cache
/**
* Object constructor.
*
* @param string $type Engine type ('db' or 'memcache' or 'apc')
* @param string $type Engine type ('db', 'memcache', 'apc', 'redis')
* @param int $userid User identifier
* @param string $prefix Key name prefix
* @param string $ttl Expiration time of memcache/apc items
@ -70,6 +70,11 @@ class rcube_cache
$this->db = $rcube->get_memcache();
$this->debug = $rcube->config->get('memcache_debug');
}
else if ($type == 'redis') {
$this->type = 'redis';
$this->db = $rcube->get_redis();
$this->debug = $rcube->config->get('redis_debug');
}
else if ($type == 'apc') {
$this->type = 'apc';
$this->db = function_exists('apc_exists'); // APC 3.1.4 required
@ -271,6 +276,9 @@ class rcube_cache
if ($this->type == 'memcache') {
$data = $this->db->get($ckey);
}
else if ($this->type == 'redis') {
$data = $this->db->get($ckey);
}
else if ($this->type == 'apc') {
$data = apc_fetch($ckey);
}
@ -344,7 +352,7 @@ class rcube_cache
return false;
}
if ($this->type == 'memcache' || $this->type == 'apc') {
if (in_array($this->type, array("memcache", "apc", "redis"))) {
$result = $this->add_record($this->ckey($key), $data);
// make sure index will be updated
@ -468,7 +476,7 @@ class rcube_cache
}
/**
* Adds entry into memcache/apc DB.
* Adds entry into memcache/apc/redis DB.
*
* @param string $key Cache key name
* @param mixed $data Serialized cache data
@ -484,6 +492,9 @@ class rcube_cache
$result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
}
}
else if ($this->type == 'redis') {
$result = $this->db->setEx($key, $this->ttl, $data);
}
else if ($this->type == 'apc') {
if (apc_exists($key)) {
apc_delete($key);
@ -500,7 +511,7 @@ class rcube_cache
}
/**
* Deletes entry from memcache/apc DB.
* Deletes entry from memcache/apc/redis DB.
*
* @param string $key Cache key name
*
@ -512,6 +523,9 @@ class rcube_cache
// #1488592: use 2nd argument
$result = $this->db->delete($key, 0);
}
else if ($this->type == 'redis') {
$result = $this->db->delete($key);
}
else {
$result = apc_delete($key);
}
@ -524,7 +538,7 @@ class rcube_cache
}
/**
* Writes the index entry into memcache/apc DB.
* Writes the index entry into memcache/apc/redis DB.
*/
private function write_index()
{
@ -553,7 +567,7 @@ class rcube_cache
}
/**
* Gets the index entry from memcache/apc DB.
* Gets the index entry from memcache/apc/redis DB.
*/
private function load_index()
{
@ -570,6 +584,9 @@ class rcube_cache
if ($this->type == 'memcache') {
$data = $this->db->get($index_key);
}
else if ($this->type == 'redis') {
$data = $this->db->get($index_key);
}
else if ($this->type == 'apc') {
$data = apc_fetch($index_key);
}
@ -582,7 +599,7 @@ class rcube_cache
}
/**
* Creates per-user cache key name (for memcache and apc)
* Creates per-user cache key name (for memcache, apc, redis)
*
* @param string $key Cache key name
*
@ -594,7 +611,7 @@ class rcube_cache
}
/**
* Creates per-user index cache key name (for memcache and apc)
* Creates per-user index cache key name (for memcache, apc, redis)
*
* @return string Cache key
*/
@ -652,7 +669,7 @@ class rcube_cache
}
/**
* Write memcache/apc debug info to the log
* Write memcache/apc/redis debug info to the log
*/
private function debug($type, $key, $data = null, $result = null)
{

@ -31,7 +31,7 @@ class rcube_cache_shared
/**
* Instance of database handler
*
* @var rcube_db|Memcache|bool
* @var rcube_db|Memcache|Redis|bool
*/
private $db;
private $type;
@ -51,9 +51,9 @@ class rcube_cache_shared
/**
* Object constructor.
*
* @param string $type Engine type ('db' or 'memcache' or 'apc')
* @param string $type Engine type ('db', 'memcache', 'apc', 'redis')
* @param string $prefix Key name prefix
* @param string $ttl Expiration time of memcache/apc items
* @param string $ttl Expiration time of memcache/apc/redis items
* @param bool $packed Enables/disabled data serialization.
* It's possible to disable data serialization if you're sure
* stored data will be always a safe string
@ -68,6 +68,11 @@ class rcube_cache_shared
$this->db = $rcube->get_memcache();
$this->debug = $rcube->config->get('memcache_debug');
}
else if ($type == 'redis') {
$this->type = 'redis';
$this->db = $rcube->get_redis();
$this->debug = $rcube->config->get('redis_debug');
}
else if ($type == 'apc') {
$this->type = 'apc';
$this->db = function_exists('apc_exists'); // APC 3.1.4 required
@ -266,6 +271,9 @@ class rcube_cache_shared
if ($this->type == 'memcache') {
$data = $this->db->get($ckey);
}
else if ($this->type == 'redis') {
$data = $this->db->get($ckey);
}
else if ($this->type == 'apc') {
$data = apc_fetch($ckey);
}
@ -339,7 +347,7 @@ class rcube_cache_shared
return false;
}
if ($this->type == 'memcache' || $this->type == 'apc') {
if (in_array($this->type, array("memcache", "apc", "redis"))) {
$result = $this->add_record($this->ckey($key), $data);
// make sure index will be updated
@ -458,7 +466,7 @@ class rcube_cache_shared
}
/**
* Adds entry into memcache/apc DB.
* Adds entry into memcache/apc/redis DB.
*
* @param string $key Cache internal key name
* @param mixed $data Serialized cache data
@ -474,6 +482,9 @@ class rcube_cache_shared
$result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
}
}
else if ($this->type == 'redis') {
$result = $this->db->setEx($key, $this->ttl, $data);
}
else if ($this->type == 'apc') {
if (apc_exists($key)) {
apc_delete($key);
@ -490,7 +501,7 @@ class rcube_cache_shared
}
/**
* Deletes entry from memcache/apc DB.
* Deletes entry from memcache/apc/redis DB.
*
* @param string $key Cache internal key name
*
@ -502,6 +513,9 @@ class rcube_cache_shared
// #1488592: use 2nd argument
$result = $this->db->delete($key, 0);
}
else if ($this->type == 'redis') {
$result = $this->db->delete($key);
}
else {
$result = apc_delete($key);
}
@ -514,7 +528,7 @@ class rcube_cache_shared
}
/**
* Writes the index entry into memcache/apc DB.
* Writes the index entry into memcache/apc/redis DB.
*/
private function write_index()
{
@ -543,7 +557,7 @@ class rcube_cache_shared
}
/**
* Gets the index entry from memcache/apc DB.
* Gets the index entry from memcache/apc/redis DB.
*/
private function load_index()
{
@ -560,6 +574,9 @@ class rcube_cache_shared
if ($this->type == 'memcache') {
$data = $this->db->get($index_key);
}
else if ($this->type == 'redis') {
$data = $this->db->get($index_key);
}
else if ($this->type == 'apc') {
$data = apc_fetch($index_key);
}
@ -572,7 +589,7 @@ class rcube_cache_shared
}
/**
* Creates cache key name (for memcache and apc)
* Creates cache key name (for memcache, apc, redis)
*
* @param string $key Cache key name
*
@ -584,7 +601,7 @@ class rcube_cache_shared
}
/**
* Creates index cache key name (for memcache and apc)
* Creates index cache key name (for memcache, apc, redis)
*
* @return string Cache key
*/

@ -34,86 +34,7 @@ class rcube_session_redis extends rcube_session {
{
parent::__construct($config);
// instantiate Redis object
$this->redis = new Redis();
if (!$this->redis) {
rcube::raise_error(array('code' => 604, 'type' => 'session',
'line' => __LINE__, 'file' => __FILE__,
'message' => "Failed to find Redis. Make sure php-redis is included"),
true, true);
}
// get config instance
$hosts = $this->config->get('redis_hosts', array('localhost'));
// host config is wrong
if (!is_array($hosts) || empty($hosts)) {
rcube::raise_error(array('code' => 604, 'type' => 'session',
'line' => __LINE__, 'file' => __FILE__,
'message' => "Redis host not configured"),
true, true);
}
// only allow 1 host for now until we support clustering
if (count($hosts) > 1) {
rcube::raise_error(array('code' => 604, 'type' => 'session',
'line' => __LINE__, 'file' => __FILE__,
'message' => "Redis cluster not yet supported"),
true, true);
}
foreach ($hosts as $host) {
// explode individual fields
list($host, $port, $database, $password) = array_pad(explode(':', $host, 4), 4, null);
// set default values if not set
$host = ($host !== null) ? $host : '127.0.0.1';
$port = ($port !== null) ? $port : 6379;
$database = ($database !== null) ? $database : 0;
if ($this->redis->connect($host, $port) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not connect to Redis server. Please check host and port"
),
true,
true
);
}
if ($password != null && $this->redis->auth($password) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not authenticate with Redis server. Please check password."
),
true,
true
);
}
if ($database != 0 && $this->redis->select($database) === false) {
rcube::raise_error(
array(
'code' => 604,
'type' => 'session',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Could not select Redis database. Please check database setting."
),
true,
true
);
}
}
$this->redis = rcube::get_instance()->get_redis();
// register sessions handler
$this->register_session_handler();

Loading…
Cancel
Save