Cache flush by system_cron() in being ignored by Memcache.
// system_cron() flushes all cache bins returned by hook_flush_caches()
// with cache_clear_all(NULL, $bin); This is for garbage collection with
// the database cache, but serves no purpose with memcache. So return
// early here.
if (!isset($cid)) {
return;
}
This is causing issues if we have enabled page caching for anonymous users and use database caching for cache_form.
When cron runs, it deletes all expired form ids from cache_form by their expire timestamp and would delete all cached pages (as they use temporary cache) if they were stored in database cache tables.
But when we use memcache, flush for pages is ignored and this results in old pages being served with form ids which do not exist anymore in cache_form, so forms on these cached pages can not be be submitted anymore until cache is flushed manually.
Comments
Comment #1
larowlanThis also occurs for block_cache where CACHE_TEMPORARY is always used for cache_set, memcache converts CACHE_TEMPORARY to 1 month or so but then *does not* flush these entries when cache_clear_all(NULL, 'cache_block') is called by system_cron (for the same reasons as above).
The result is that blocks are cached for 1 month and survive a cron run.
Comment #2
onelittleant commentedI'm surprised that there is not further discussion here. Does anyone have a recommendation for how to handle the CACHE_TEMPORARY issue? My thought at the very least is that CACHE_TEMPORARY should be trated as no more than one day by memcache, or should be configurable. 1 month is just absurd. It makes the block cache truly useless for blocks containing any kind of dynamic content. What about and admin setting to choose the duration of CACHE_TEMPORTARY employed by memcache?
Comment #3
markpavlitski commentedThis patch fixes the issue and adds test coverage to confirm that memcache responds in the same way as DrupalDatabaseCache when calling
cache_clear_all(NULL, $bin).Comment #4
acbramley commentedI'm having the same issue. I have some data stored in cache temp which gets retrieved on cron runs. We just had a bug report saying that the data hadn't been updated in months, turns out this is the issue! Will report with results from patch
Comment #5
acbramley commentedCan confirm this fixes my issues perfectly, cheers!
Comment #6
acbramley commentedJust a note, this is not specific to cache_form but anything using CACHE_TEMPORARY
Comment #7
damontgomery commentedWe are having the exact same issue. I'm going to try the patch.
I created a custom module with CACHE_TEMPORARY and without memcache it works as expected. With memcache (on prod), it doesn't get cleared.
Comment #8
damontgomery commented#3 Worked for our custom module using CACHE_TEMPORARY. Everything seems to clear as expected.
Comment #9
adammaloneComment #10
larowlan+1 rtbc
Comment #11
deviantintegral commentedFixing a typo of "exirable" in the test comments.
Comment #12
markpavlitski commentedWell spotted!
Setting back to needs review and interdiff attached for patch in #11 vs #3 to speed things up.
Comment #13
markpavlitski commentedComment #14
topham commentedThis issue seems to be the underlying cause of a problem on my site. We have some time-based content which should be updated throughout the day, and over night however it was only getting updated sporadically throughout the day. I've traced the issue to the handling of cache_clear_all(NULL,$bin) being a NO-OP on memcache. The reason content was sporadically being updated (as opposed to never) during the day was that any call to "node_form_submit()" would then call "cache_clear_all()" with no parameters which seems to be handled differently than "cache_clear_all(NULL,$bin)".
My fix until this patch gets further along is to call "cache_clear_all()" during every cron run.
Comment #15
markpavlitski commentedSetting back to RTBC. It's only a minor comment change and still applies cleanly to 7.x-dev.
Comment #16
jeremy commentedThanks! This is an important fix. Patch committed:
http://drupalcode.org/project/memcache.git/commit/5c52cff
Comment #18
emsearcy commentedI came across this while reviewing changes since 7.x-1.0.
It looks like the committed fix doesn't address invalidating CACHE_TEMPORARY in a way that supports stampede protection.
Also, I was thinking whether a second array key is really needed for this. Aside from some slight overhead, I think the code could be more understandable if the original $expire was what was stored in the cache item, and that include the CACHE_TEMPORARY value. The current use of $cache->expire to start calculating an expiration, which then transitions to $memcache_expire to calculate a later time for stampede protection, doesn't read very well IMO.
I'd propose solely using $memcache_expire variable to calculate each of the different cache expiration cases (REQUEST_TIME+30days for temporary, x2 for permanent, etc), and passing through the original timestamp.
I might have an initial revision done tonight, but if not I'd appreciate any feedback on the idea.
Comment #19
jeremy commentedI'm happy to take a look at your patch, marking this as active to reflect this; please update to needs review once you attach your patch.
Comment #20
damienmckennaThis may be related to a bug I found elsewhere: #2366709: memcache_requirements() returns 'failed to store then retrieve data' on Windows
Comment #21
emsearcy commentedWhile trying to refactor this for my recommendations in #18 (retain original $expires parameter into the cache object instead of adding $cache->temporary, and support stampede protection for expired entries), I ran into a dilemma. The memcache module has traditionally not lined up with the API's definition of cache_set, namely, that an expired item behaves the same as CACHE_TEMPORARY (still valid until "general cache wipe"). This may be considered a limitation of how DB caching works (that it requires garbage collection), but the fact remains that cache_set with memcache module doesn't behave the way the API says it should. I don't know what is preferred, so I added a variable that allows the module to function the same way as described in the API, but leaving the traditional behavior as the default. Also, if stampede protection is disabled and the traditional behavior (exact timestamp expirations) is kept, I changed it so that the exact expiration is passed to memcached. This was the behavior before stampede protection was added, and for those not using stampede protection, it means a slightly smaller cache and less cache hits retrieved across the wire which just end up failing valid().
This fails 3 tests in cache clearing, but these tests already were failing for me in 7.x-1.x (I suspect it's due to a REQUEST_TIME/time() discrepancy).
I can split this into multiple patches if that is preferred.
Comment #22
markpavlitski commentedUpdating status now that a patch is available.
Comment #23
fabianx commentedChanging summary
Comment #24
damienmckennaRerolled.
Comment #26
jeremy commentedThanks, applied!