Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not treat an empty array as not set in caches. #12784

Merged
merged 6 commits into from
Oct 10, 2018

Conversation

eileenmcnaughton
Copy link
Contributor

Overview

Reduce cache miss calls by respecting empty arrays as a cache hit

Before

Cache calls which return empty arrays are treated as misses

After

Cache calls which return empty arrays are treated as hits

Technical Details

On testing Redis we found that even after Redis cache had been
built the set function was still being called. It turned out the reason is that
when a value was set to an empty array that was being treated as FALSEY.

In fact the cache function returns NULL if nothing is set & no default is
specified & we should only treat NULL as a cache miss

Comments

As an aside Our testing is showing a speed decrease when we switch from Array Caching to Redis caching. My thinking is that array caching is in fact more efficient & ideally it would be array caching & fall back on Redis caching - so if not loaded this session that is where it loads from. That is how the BAO_Cache::getItem function works but the Civi::cache()->get does not.

On testing Redis we found that even after Redis cache had been
built the set function was still being called. It turned out the reason is that
when a value was set to an empty array that was being treated as FALSEY.

In fact the cache function returns NULL if nothing is set & no default is
specified & we should only treat NULL as a cache miss
@@ -75,7 +75,7 @@ public static function &getItem($group, $path, $componentID = NULL) {
$cache = CRM_Utils_Cache::singleton();
$cleanKey = self::cleanKey($argString);
self::$_cache[$argString] = $cache->get($cleanKey);
if (!self::$_cache[$argString]) {
if (self::$_cache[$argString] === NULL) {
Copy link
Member

@totten totten Sep 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside: on skimming, I had a knee-jerk reaction of using isset()/array_key_exists() and about handling of literal NULL values... but the line as written does make sense.

Firstly, we are guaranteed to have some value in this line (b/c of the preceding $cache->get()), so we don't need to be paranoid about the notation for reading self::$_cache.

Secondly, there is arguably an issue when the value is a purposeful NULL (i.e. it still does the extra lookup), but that's a rare scenario, and the cure would likely be as bad as the disease. How so? To disambiguate a purposeful NULL from a cache-miss-NULL, you either need to change the contract for $cache (veering away from PSR-16) or do an extra lookup ($cache->has(...)). The former is unpleasant from a qualitative/architectural standpoint. The latter would add an extra Redis lookup for all cache-misses (somewhat common) in order to avoid a SQL lookup for NULL values (uncommon). Evaluating that micro-optimization turns into numbers game that I don't really want to play. It's easier to KISS.

Generally, I think this PR is doing good if it just improves the cache performance for other FALSE-ish values (0, '0', FALSE, array()). Don't sweat NULL.

For some reason, lost in svn days, the membershipType pseudoconstant
is set to not use the cache by passing  = true.

It was probably test frustration & does not make sense now
@totten totten added the master label Sep 6, 2018
@seamuslee001
Copy link
Contributor

Jenkins re test this please

@seamuslee001
Copy link
Contributor

@eileenmcnaughton should this be against 5.6

@eileenmcnaughton
Copy link
Contributor Author

@seamuslee001 I don't think it's a regression - just something not identified earlier

@eileenmcnaughton
Copy link
Contributor Author

test this please

@eileenmcnaughton
Copy link
Contributor Author

@seamuslee001 we have deployed this in production - my feeling is that it should be 'merge on pass' from the above & got derailed by the server issues - do you agree?

@seamuslee001
Copy link
Contributor

yeh i'm good with that Tim seems fine with it adding merge on pass

@seamuslee001
Copy link
Contributor

test failures unrelated merging as per the tag

@seamuslee001 seamuslee001 merged commit d9bb65a into civicrm:master Oct 10, 2018
@eileenmcnaughton eileenmcnaughton deleted the cache branch October 10, 2018 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants