Problem/Motivation

If wildcards are used to clear the cache (cache_clear_all('filter_list_format', 'cache', TRUE);), the cache isn't cleared as expected.
A full cache clear by using cache_clear_all('*', 'cache', TRUE) works as expected.

Steps to reproduce:

Using Filter Formats
  1. Open a filter and change its settings
  2. Save settings
  3. Re-open the same filter again:
    Expected: Form reflects changes.
    Actual: Form reflects the old settings.
  4. Flush cache
  5. Re-open the same filter again - now the form reflects the new settings.
Using Menu
  1. Open Menu Link and change its label
  2. Save changes
  3. Check if the change is reflected in the frontend:
    Expected: Menu link label has changed.
    Actual: Menu link label is still the same.
  4. Flush cache.
  5. Check again if the change is reflected in the frontend: - now the menu link label has changed.

Looks like this is a follow-up of one of the various other wildcart issues we had:

Please have a look at the new tests added with the patch in #1344036-1: Backport tests from: Cache clear fails when using wildcards - strange behavior with wildcard_valid()

Proposed resolution

Make sure the proper cache key is used for increment in wildcards().

Remaining tasks

  1. Review the patch in #4
  2. Feedback for #6 very welcome

User interface changes

none

API changes

none

Original report by weri

We have some strange behaviours when memcache is enabled. For example: The format edit form (admin/config/content/formats/full_html).

When we change the enabled filters and safe the configuration, after the request the "old" checkboxes are selected. The changes are saved in the database but the settings are loaded from the cache (cache_get('filter_list_format') in filter.module). But the cached data is cleared after the form submit in the function filter_formats_reset() (cache_clear_all('filter_list_format', 'cache', TRUE);).

When I insert a cache_get('filter_list_format') directly after the cache_clear_all('filter_list_format', 'cache', TRUE), the return value is FALSE. That's correct, but after the form submission (drupal_goto()) the next cache_get('filter_list_format') loads the "old" object from cache and does not return FALSE anymore and prevent the module to load the settings from the database and store the new values with cache_set (filter.module line 660 in the function filter_list_format($format_id)).

When i change cache_clear_all('filter_list_format', 'cache', TRUE) to cache_clear_all('*', 'cache', TRUE), everything is cleared correctly and the settings are updated.

I could reproduce this behaviour on two different Drupal 7.9 installations.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

das-peter’s picture

I didn't have the time for actual bug-hunting yet, but I've created a new test class to use the menu to verify the bug.
How to use the new test:

  • Apply patch.
  • Make sure you've enabled memcache in your settings.php
  • Run the new memcache test: Real world cache tests
  • Test fails
  • Disable memcache in your settings.php
  • Run the new memcache test: Real world cache tests
  • Test passes
das-peter’s picture

Title: Strange behavior with wildcard_valid() » Cache clear fails when using wildcards - strange behavior with wildcard_valid()
Status: Active » Needs work

Added summary according to the Issue summary standards.
Modified title to be more general.

catch’s picture

Priority: Major » Critical

Bumping to critical, this should block a 1.0 release.

das-peter’s picture

I can't believe how long I now debugged to fix this single line...
Root cause of the whole issue was that MemCacheDrupal::wildcards() didn't use dmemcache_key() on this particular line but for lookup dmemcache_get_multi() is used which internally uses dmemcache_key().
That way the whole counting became inconsistent.

I've tried to another approach to create tests to cover that but I wasn't able to figure out how to really test that, nevertheless I've attached a patch with what I tried.
The tests I've added in #1 pass now.

das-peter’s picture

Status: Needs work » Needs review

Oh of course this needs review now :)

das-peter’s picture

Before I forget it: Another change I thought of is to replace the increment by a set.
Currently:

        $this->memcache->increment(dmemcache_key($key, $this->bin));
         $wildcards[$this->bin][$key]++;

Idea:

        $wildcards[$this->bin][$key]++;
        $this->memcache->set(dmemcache_key($key, $this->bin), $wildcards[$this->bin][$key]);

Advantage of this would be that even if initially something went wrong the value is later properly set. Because if you use increment it wont create a item if it doesn't already exist.

das-peter’s picture

Issue summary: View changes

Changed summary to fit the new summary initiative standards

Berdir’s picture

Using set() instead of increment() sounds interesting, especially because we could then use the dmemcache_set() helper function, so that the encoding of the $key is again consistently encapsulated by dmemcache_*() functions.

Will look into the tests if I find the time.

weri’s picture

I applied the patch #4 and it resolved our problem.

Berdir’s picture

Ok, you were actually quite close with your tests, all I had to do was adding a second round of set/get/clear/get because the initial wildcard is written using dmemcache_set() which correctly encoded $key.

The attached patch now consistently uses dmemcache_set() to write the wildcard. This might be bit slower but is way more failure tolerant (e.g. memcache restarts) and consistent.

The attached patch passed all tests for me locally.

das-peter’s picture

Awesome! Thanks for your effort.
dmemcache_set() sounds very good to me. Code will be more consistent and maybe somewhat self-healing within the same request :D

catch’s picture

Version: 7.x-1.0-rc2 » 6.x-1.x-dev
Category: bug » task
Priority: Critical » Normal
Status: Needs review » Patch (to be ported)

This all makes sense, I've committed/pushed to 7.x-1.x.

We should backport the tests, and possibly the set/get change to 6.x (the increment usage is correct there though since it uses dmemcache_key(), so dropping priority for the backport).

catch’s picture

Title: Cache clear fails when using wildcards - strange behavior with wildcard_valid() » Backport tests from: Cache clear fails when using wildcards - strange behavior with wildcard_valid()

Re-titling.

Cyberwolf’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev

I am still encountering the same issue, both with memcache-7.x-1.0 as 7.x-1.x-dev (2012-Jan-30) releases. I have the following configuration in settings.php (I replaced the IP with ***):

$conf['memcache_servers'] = array('***:11211' => 'default');
$conf['cache_backends'] = array('sites/all/modules/memcache/memcache.inc');
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

When I add the following modifying input formats works again like it should:

$conf['cache_class_cache'] = 'DrupalDatabaseCache';

But of course we also want to use Memcache for the general cache bin.

catch’s picture

Version: 7.x-1.x-dev » 6.x-1.x-dev

@Cyberwolf, 'same issue' isn't enough information, and the fact we added simpletests here suggests you're most likely hitting a different bug. I'm going to move this back to 6.x for the test backport, however please open a new bug, against 7.x, with clear steps to reproduce (ideally starting with a clean install of Drupal 7 + memcache 7.x-1.0 and nothing else), thanks!

Cyberwolf’s picture

I will specify more clearly what I mean with 'the same issue' then: I am unable to modify input formats with memcache-7.x-1.0 or 7.x-1.x-dev (2012-Jan-30) releases with the following configuration in settings.php:

$conf['memcache_servers'] = array('***:11211' => 'default');
$conf['cache_backends'] = array('sites/all/modules/memcache/memcache.inc');
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

It's exactly the same behavior as described in the original report by weri.

Will retry on a completely clean install and let you know if it works now or not.

Berdir’s picture

Also make sure that you're not using a broken memcache extension or server, see http://drupal.org/node/1131470

Cyberwolf’s picture

That probably explains everything, we are indeed using PECL memcache 3.0.4 which apparently has a bug with wildcard flushes. I'll ask our sysadmins to update to a newer version. Thanks @Berdir for pointing me in the right direction!

Cyberwolf’s picture

The memcache extension was upgraded and now it works correctly here with the Drupal memcache module 7.x-1.x-dev.

Cyberwolf’s picture

Issue summary: View changes

Updated issue summary.