Skip to content

Commit

Permalink
Modify cache redis backend
Browse files Browse the repository at this point in the history
# Changes

1. Modify cache redis backend, delete _PHCR
2. Cache redis backend supports "client" option, now you can pass a redis client

# Why

1. The redis cache backend use a special key _PHCR to store all keys used by cache. There is a issue: phalcon#10905 .According to @Green-Cat ,it is disabled in 2.0.x branch which is not true. If use _PHCR, every time we set a cache, we have to run sAdd and set commands. Store all keys in _PHCR will cause it expands quickly and this will influence performance.
2. The previous implementation mixes statsKey and prefix, it uses _PHCR as super prefix which is not needed.
3. The cache backend doesn't support redis option which means that we can not pass a redis connection. So if we use modelsCache and modelsMetadata, there will be two redis connections. So I modify this part and let redis option be supported, and through the lifetime of a request we can use one redis connection.
  • Loading branch information
pantaovay committed Mar 30, 2016
1 parent 6e8f6c7 commit 3cacd54
Showing 1 changed file with 54 additions and 133 deletions.
187 changes: 54 additions & 133 deletions phalcon/cache/backend/redis.zep
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class Redis extends Backend implements BackendInterface
let options = [];
}

if isset options["client"] && typeof options["client"] == "object" && options["client"] instanceof \Redis {
let this->_redis = options["client"];
}

if !isset options["host"] {
let options["host"] = "127.0.0.1";
}
Expand All @@ -88,13 +92,21 @@ class Redis extends Backend implements BackendInterface
}

if !isset options["statsKey"] {
// Disable tracking of cached keys per default
let options["statsKey"] = "";
let options["statsKey"] = "_PHCR";
}

parent::__construct(frontend, options);
}

public function _getRedis()
{
if typeof this->_redis != "object" {
this->_connect();
}

return this->_redis;
}

/**
* Create internal connection to redis
*/
Expand All @@ -116,7 +128,7 @@ class Redis extends Backend implements BackendInterface
}

if !success {
throw new Exception("Could not connect to the Redisd server ".host.":".port);
throw new Exception("Could not connect to the Redisd server " . host . ":" . port);
}

if fetch auth, options["auth"] {
Expand Down Expand Up @@ -147,29 +159,20 @@ class Redis extends Backend implements BackendInterface
*/
public function get(keyName, lifetime = null)
{
var redis, frontend, prefix, lastKey, cachedContent;
var lastKey, cachedContent;

let redis = this->_redis;
if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}

let frontend = this->_frontend;
let prefix = this->_prefix;
let lastKey = "_PHCR" . prefix . keyName;
let lastKey = this->_prefix . keyName;
let this->_lastKey = lastKey;
let cachedContent = redis->get(lastKey);

let cachedContent = this->_getRedis()->get(lastKey);
if !cachedContent {
return null;
}

if is_numeric(cachedContent) {
return cachedContent;
}

return frontend->afterRetrieve(cachedContent);
return this->_frontend->afterRetrieve(cachedContent);
}

/**
Expand All @@ -182,39 +185,24 @@ class Redis extends Backend implements BackendInterface
*/
public function save(keyName = null, content = null, lifetime = null, boolean stopBuffer = true)
{
var prefixedKey, lastKey, prefix, frontend, redis, cachedContent, preparedContent,
tmp, tt1, success, options, specialKey, isBuffering;
var lastKey, frontend, cachedContent, preparedContent, ttl, success, specialKey, isBuffering;

if keyName === null {
if !keyName {
let lastKey = this->_lastKey;
let prefixedKey = substr(lastKey, 5);
} else {
let prefix = this->_prefix;
let prefixedKey = prefix . keyName;
let lastKey = "_PHCR" . prefixedKey;
let lastKey = this->_prefix . keyName;
}

if !lastKey {
throw new Exception("The cache must be started first");
}

let frontend = this->_frontend;

/**
* Check if a connection is created or make a new one
*/
let redis = this->_redis;
if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}

if content === null {
let cachedContent = frontend->getContent();
} else {
let cachedContent = content;
}

/**
* Prepare the content in the frontend
*/
Expand All @@ -223,45 +211,35 @@ class Redis extends Backend implements BackendInterface
}

if lifetime === null {
let tmp = this->_lastLifetime;

if !tmp {
let tt1 = frontend->getLifetime();
if !this->_lastLifetime {
let ttl = frontend->getLifetime();
} else {
let tt1 = tmp;
let ttl = this->_lastLifetime;
}
} else {
let tt1 = lifetime;
let ttl = lifetime;
}

if is_numeric(cachedContent) {
let success = redis->set(lastKey, cachedContent);
let success = this->_getRedis()->set(lastKey, cachedContent, ttl);
} else {
let success = redis->set(lastKey, preparedContent);
let success = this->_getRedis()->set(lastKey, preparedContent, ttl);
}

if !success {
throw new Exception("Failed storing the data in redis");
}

redis->settimeout(lastKey, tt1);

let options = this->_options;

if !fetch specialKey, options["statsKey"] {
if !fetch specialKey, this->_options["statsKey"] {
throw new Exception("Unexpected inconsistency in options");
}

if specialKey != "" {
redis->sAdd(specialKey, prefixedKey);
this->_getRedis()->sAdd(specialKey, lastKey);
}

let isBuffering = frontend->isBuffering();

if stopBuffer === true {
frontend->stop();
}

if isBuffering === true {
echo cachedContent;
}
Expand All @@ -277,31 +255,21 @@ class Redis extends Backend implements BackendInterface
*/
public function delete(keyName)
{
var redis, prefix, prefixedKey, lastKey, options, specialKey;
var lastKey, specialKey;

let redis = this->_redis;
if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}

let prefix = this->_prefix;
let prefixedKey = prefix . keyName;
let lastKey = "_PHCR" . prefixedKey;
let options = this->_options;
let lastKey = this->_prefix . keyName;

if !fetch specialKey, options["statsKey"] {
if !fetch specialKey, this->_options["statsKey"] {
throw new Exception("Unexpected inconsistency in options");
}

if specialKey != "" {
redis->sRem(specialKey, prefixedKey);
this->_getRedis()->sRem(specialKey, lastKey);
}

/**
* Delete the key from redis
*/
return redis->delete(lastKey);
return this->_getRedis()->delete(lastKey);
}

/**
Expand All @@ -312,29 +280,19 @@ class Redis extends Backend implements BackendInterface
*/
public function queryKeys(prefix = null)
{
var redis, options, keys, specialKey, key, value;

let redis = this->_redis;

if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}
var keys, specialKey, key, value;

let options = this->_options;

if !fetch specialKey, options["statsKey"] {
if !fetch specialKey, this->_options["statsKey"] {
throw new Exception("Unexpected inconsistency in options");
}

if specialKey == "" {
throw new Exception("Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCM')!");
throw new Exception("Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCR')!");
}

/**
* Get the key from redis
*/
let keys = redis->sMembers(specialKey);
let keys = this->_getRedis()->sMembers(specialKey);
if typeof keys == "array" {
for key, value in keys {
if prefix && !starts_with(value, prefix) {
Expand All @@ -355,26 +313,16 @@ class Redis extends Backend implements BackendInterface
*/
public function exists(keyName = null, lifetime = null) -> boolean
{
var lastKey, redis, prefix;
var lastKey;

if !keyName {
let lastKey = this->_lastKey;
} else {
let prefix = this->_prefix;
let lastKey = "_PHCR" . prefix . keyName;
let lastKey = this->_prefix . keyName;
}

if lastKey {
let redis = this->_redis;
if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}

if !redis->get(lastKey) {
return false;
}
return true;
return this->_getRedis()->exists(lastKey);
}

return false;
Expand All @@ -389,28 +337,20 @@ class Redis extends Backend implements BackendInterface
*/
public function increment(keyName = null, value = null)
{
var redis, prefix, lastKey;

let redis = this->_redis;

if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}
var lastKey;

if !keyName {
let lastKey = this->_lastKey;
} else {
let prefix = this->_prefix;
let lastKey = "_PHCR" . prefix . keyName;
let lastKey = this->_prefix . keyName;
let this->_lastKey = lastKey;
}

if !value {
let value = 1;
}

return redis->incrBy(lastKey, value);
return this->_getRedis()->incrBy(lastKey, value);
}

/**
Expand All @@ -422,60 +362,41 @@ class Redis extends Backend implements BackendInterface
*/
public function decrement(keyName = null, value = null)
{
var redis, prefix, lastKey;

let redis = this->_redis;

if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}
var lastKey;

if !keyName {
let lastKey = this->_lastKey;
} else {
let prefix = this->_prefix;
let lastKey = "_PHCR" . prefix . keyName;
let lastKey = this->_prefix . keyName;
let this->_lastKey = lastKey;
}

if !value {
let value = 1;
}

return redis->decrBy(lastKey, value);
return this->_getRedis()->decrBy(lastKey, value);
}

/**
* Immediately invalidates all existing items.
*/
public function flush() -> boolean
{
var options, specialKey, redis, keys, key, lastKey;
var specialKey, keys, key;

let options = this->_options;

if !fetch specialKey, options["statsKey"] {
if !fetch specialKey, this->_options["statsKey"] {
throw new Exception("Unexpected inconsistency in options");
}

let redis = this->_redis;

if typeof redis != "object" {
this->_connect();
let redis = this->_redis;
}

if specialKey == "" {
throw new Exception("Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCM')!");
throw new Exception("Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCR')!");
}

let keys = redis->sMembers(specialKey);
let keys = this->_getRedis()->sMembers(specialKey);
if typeof keys == "array" {
for key in keys {
let lastKey = "_PHCR" . key;
redis->sRem(specialKey, key);
redis->delete(lastKey);
this->_getRedis()->sRem(specialKey, key);
this->_getRedis()->delete(key);
}
}

Expand Down

0 comments on commit 3cacd54

Please sign in to comment.