The Problem:
We wanted to be able to support two versions (look and feel) of the site with the same URLs for each. (Yes, we have very good reasons for this.) But we did not want to sacrifice package caching performance. Ideally, what we want is separate page cache variants for the theme.
Potential Solution:
One way of solving this problem is to use cookies to distinguish which of the two versions the client should get. Then, we can route traffic accordingly. To get page cache to store two versions of the page, we need to distinguish the keys for one version from those of the other version.
Attached is a small patch that generates cache variants based on cookies. It should be moderately extensible. While perhaps a core patch would be better suited for this sort of thing, that's not realistic for either D6 r D7 at this point. So I figure that this is the right place to implement such a feature.
Anyone have any thoughts about this method? Pros? Cons? Alternatives that don't involve massive amounts of path/q munging?
About the Patch:
The patch adds a short function to memcache.inc that transforms $cids.
function memcache_cookie_variant_cid($cid, $table) {
global $conf;
if ($table != 'cache_page') return $cid;
foreach ($conf['cookie_page_cache_variants'] as $cookie => $prefix) {
if (!empty($_COOKIE[$cookie])) {
return $prefix . $cid;
}
}
return $cid;
}
The function is called during cache_get/set/clear calls. In settings.php (or anything called very early in bootstap), one can specify a new variant cookie like this:
$conf['cookie_page_cache_variants'] = array('my_cookie_name' => 'my_prefix-');
This would result in a memcache key that would look something like this:
cache_page-my_prefix-http%3A%2F%2Fexample.com%2Ffoo%2Fbar
Comment | File | Size | Author |
---|---|---|---|
#11 | memcache-942914-11-D6.patch | 2 KB | mikeytown2 |
#3 | memcache-942914.patch | 3.77 KB | mikeytown2 |
#2 | memcache-942914.patch | 3.75 KB | mikeytown2 |
memcache.inc-20101015.patch | 2.81 KB | mbutcher |
Comments
Comment #1
mikeytown2 CreditAttribution: mikeytown2 commentedComing over from #952620: Set different page cache ID based off of cookie that is set from a custom organic group module.
I recommend following something similar to core's url rewriting
http://api.drupal.org/api/function/custom_url_rewrite_inbound/6 => http://api.drupal.org/api/function/drupal_get_normal_path/6
http://api.drupal.org/api/function/custom_url_rewrite_outbound/6 => http://api.drupal.org/api/function/url/6
As in don't call the function unless it's defined & let a external module define it.
Comment #2
mikeytown2 CreditAttribution: mikeytown2 commenteddefine function name in settings.php.
Comment #3
mikeytown2 CreditAttribution: mikeytown2 commentedupdated patch to pass the operator along.
below is an example from my settings.php file
This has other use cases; stripping useless query strings from the URL for higher cache hits, etc... If your wondering I want a cache miss if set_default is set.
Comment #4
mikeytown2 CreditAttribution: mikeytown2 commentedComment #5
mbutcher CreditAttribution: mbutcher commentedI like this patch and am testing it out. It seems to meet our requirements nicely. And as you pointed out, it can be adapted to a wide variety of similar cases. I'll update the ticket when I've finished reviewing.
Comment #6
mbutcher CreditAttribution: mbutcher commentedMaybe it'd be better to factor the common logic from the three memcache.inc functions into its own function like this (untested):
And then call this function in the get/set/clear functions.
This would probably be more maintainable over the long term.
Comment #7
mbutcher CreditAttribution: mbutcher commentedTested and working.
Comment #8
catchApart from early bootstrap (and we could check current bootstrap phase there), is there a reason not to do this as a hook?
Could have hook_memcache_cid_alter(), and it wouldn't hurt to have hook_memcache_bin_alter() - for example to route certain items to the cache_bootstrap bin.
Comment #9
mikeytown2 CreditAttribution: mikeytown2 commentedcache_bootstrap bin; looking to backport some D7 magic? Sounds interesting. So in order for this to work the module has to declare a hook_boot?
_drupal_bootstrap() does the cache call before
require_once './includes/module.inc';
is ran. This would require a require_once call for every cache operation; or hack core to move this file above thepage_get_cache();
. How do you see it done?Comment #10
catchThe idea would be to cache something like field info in the cache_bootstrap bin - however this is both requested and cached after full bootstrap has occurred, so no need to define hook_boot().
Existing stuff that's sent to cache_bootstrap I don't see any particular reason to mess with, or at least the feature could be added without supporting that.
Also I don't have a real use case for this yet, it was just an example ;)
Comment #11
mikeytown2 CreditAttribution: mikeytown2 commentedupdated the patch to the latest dev version of memcache
Comment #12
avergara CreditAttribution: avergara commentedThis could be something that I am really looking for. But the problem is, we are using APC instead of memcache. Can anyone guide me how I can implement this on APC? Thanks.
Comment #13
avergara CreditAttribution: avergara commentedComment #14
mikeytown2 CreditAttribution: mikeytown2 commented@avergara
I would start an issue over here http://drupal.org/project/apc
Comment #15
Jeremy CreditAttribution: Jeremy commentedSorry, this is an old ticket -- but, before it can be merged it needs to include an update to the README to document the new feature.