From fbebc7a0bbafb9cc5b5e5624032b04fe0b0a58b4 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 29 Mar 2018 17:11:45 -0700 Subject: [PATCH] (dev/core#174) CRM_Utils_Cache_Redis::flush() - Respect prefixes When flushing caches for an instance of `CRM_Utils_Cache_Redis`, you should only delete the items with the matching prefix. For example, we have two cache services for `js_strings` and `community_messages`. These caches always use the same backend with different naming/prefixes. The backend depends on the system configuration... might be Redis, Memcache, or SqlGroup. Let's suppose the configuration is `Redis`. To consider the before/after, it helps to have these two snippets for reference: ``` 1: Civi::cache('js_strings')->flush(); 2: Civi::cache('community_messages')->flush(); ``` Before ------ Flushing `js_strings` has the side-effect of flushing everything else in Redis, such as `community_messages`. After ----- Flushing `js_strings` only flushes `js_strings`. Comments -------- The example above focuses on two relatively obscure caches. In the future, as part of dev/core#174, it will become possible to store sessions in Redis. And then it will be more important -- e.g. if a user creates a custom-field, you do want to flush one set of data (e.g. the contact-fields cache), but you don't want to flush another (e.g. the user sessions). The current commit fixes Redis. Although it's outside the scope of this commit, here's an assessment of other drivers: * `APCcache`, `ArrayCache`, `NoCache` should be fine already. * `SqlGroup` is sort of right, sort of not. Another patch will address that. * `Memcache` and `Memcached` look like they have the same bug. I don't have these systems locally, so I haven't tried to patch. --- CRM/Utils/Cache/Memcache.php | 1 + CRM/Utils/Cache/Memcached.php | 1 + CRM/Utils/Cache/Redis.php | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CRM/Utils/Cache/Memcache.php b/CRM/Utils/Cache/Memcache.php index e7455bd498..630589e3d8 100644 --- a/CRM/Utils/Cache/Memcache.php +++ b/CRM/Utils/Cache/Memcache.php @@ -142,6 +142,7 @@ class CRM_Utils_Cache_Memcache implements CRM_Utils_Cache_Interface { * @return mixed */ public function flush() { + // FIXME: Only delete items matching `$this->_prefix`. return $this->_cache->flush(); } diff --git a/CRM/Utils/Cache/Memcached.php b/CRM/Utils/Cache/Memcached.php index e80b1af4b3..07315e53ce 100644 --- a/CRM/Utils/Cache/Memcached.php +++ b/CRM/Utils/Cache/Memcached.php @@ -164,6 +164,7 @@ class CRM_Utils_Cache_Memcached implements CRM_Utils_Cache_Interface { * @return mixed */ public function flush() { + // FIXME: Only delete items matching `$this->_prefix`. return $this->_cache->flush(); } diff --git a/CRM/Utils/Cache/Redis.php b/CRM/Utils/Cache/Redis.php index 0cfccdf80f..4988b8beef 100644 --- a/CRM/Utils/Cache/Redis.php +++ b/CRM/Utils/Cache/Redis.php @@ -154,7 +154,12 @@ class CRM_Utils_Cache_Redis implements CRM_Utils_Cache_Interface { * @return mixed */ public function flush() { - return $this->_cache->flushDB(); + // FIXME: Ideally, we'd map each prefix to a different 'hash' object in Redis, + // and this would be simpler. However, that needs to go in tandem with a + // more general rethink of cache expiration/TTL. + + $keys = $this->_cache->keys($this->_prefix . '*'); + return $this->_cache->del($keys); } } -- 2.25.1