Hello,

Since you use the global 'cache' table for strongarm misc. caches, you don't need to implement the hook_flush_caches() because Drupal will handle this table by itself.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pounard’s picture

If you remove this hook implementation, you will need to fix the function strongarm_form_system_module_alter() function in order to manually flush the caches you need to flush there.

pounard’s picture

And also the strongarm_admin_revert_submit() function.

Grep never lies.

pounard’s picture

Plus, useless cache clear will occur at cron run time if you let this useless implementation, thus wipeout out caches that still are valid. This will cause, maybe minimal, but still useless, cache miss and rebuild occurs.

crea’s picture

Priority: Normal » Critical

This is not only useless: this is an api breakage. Hook_flush_caches() is an informational hook to tell Drupal names of cache tables (bins) which needs to be flushed (to invalidate & expire old items). Any module could run this hook, killing variable cache in the process. This can put great stress on the system.

pounard’s picture

This is an old issue, I'll look again at the code.

pounard’s picture

This is not only useless: this is an api breakage. Hook_flush_caches() is an informational hook to tell Drupal names of cache tables (bins) which needs to be flushed (to invalidate & expire old items).

Yes, I know how to read api.drupal.org myself.

See this code (strongarm.module, line 119):

/**
 * Implementation of hook_flush_caches().
 */
function strongarm_flush_caches() {
  cache_clear_all('variables', 'cache');
  cache_clear_all('strongarm', 'cache');
}

When cache clear all is triggered, the hook_flush_caches() is called, right? This code basically does an explicit delete of CID variables and strongarm in the cache BIN when it's called, still following me?

But now, look at that (common.inc, around line 3700):

function drupal_flush_all_caches() {
 
  // removed some code here  ...

  // Don't clear cache_form - in-progress form submissions may break.
  // Ordered so clearing the page cache will always be the last action.
  $core = array('cache', 'cache_block', 'cache_filter', 'cache_page');
  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
  foreach ($cache_tables as $table) {
    cache_clear_all('*', $table, TRUE);
  }
}

Core flushes the cache BIN completely. If I read correctly, your implementation is called during the module_invoke_all() right before. You explicitly drop two specific CID which are being wiped out right after.

Your implementation is useless (in 6.x-2.0 version, at least), you finally do 2 useless SQL queries.

This makes the ...

/**
 * Implementation of hook_form_alter() for system_module form.
 * Clear strongarm & variable caches on modules page.
 */
function strongarm_form_system_module_alter(&$form, &$form_state) {
  strongarm_flush_caches();
}

... so wrong, because you named your own function like a hook, and basically it doubles what the core already does when it calls the hook, moreover, you call at a place where it is probably already being called at some point.

Any module could run this hook, killing variable cache in the process. This can put great stress on the system.

EDIT: Removed wrong wrong argument here. I totally support crea for this, and strongarm shouldn't itself!

crea’s picture

@pounard I don't understand why you are arguing with me. I'm against the approach.

A lot of modules does, they are poorly code, you shouldn't be dependent of bad/tired/dump developers.

Please, read system_cron() and don't spread this false information. Yes you may not like the API, but its there: hook_flush_caches() implementations should return cache table names. You are not supposed to make any assumtptions about it. Any module can run this hook just to get names. This doesn't mean the module is going to actually flush the cache.

drupal_flush_all_caches() is not the reason of the problem. Yes, hook_flush_caches() is useless together with drupal_flush_all_caches(). It is because of the system_cron() this stuff is really evil. System module expires old cache entries on cron and uses hook_flush_caches() to get target cache table names. So depending on cron frequency variable and strongarm cache will be emptied, leading to higher load when rebuilding the stuff.

pounard’s picture

@crea Ohhh sorry I totally misread what you said (I though you were arguing my point). Being non native english speaker doesn't help... Ok, nevertheless my points remain true. I'm going to edit my initial post about that, sorry again.

Yes, but this is not false information, you are true about the hook, I acknowledged that. People that made themselves queries in that hook are severely doing it wrong! That's one of the things I'm pointing in my posts, and one other is that the module doesn't respect the hook signature.

Agree with system_cron(), it's bad, there is actually a lot of modules that does ugly stuff in hook_flush_caches() but test if it's actually the cron running them before (that is a really ugly hack).

crea’s picture

Priority: Critical » Major

On a second thought, this is not critical, but still is pretty important.

pounard’s picture

Yes, just a matter of having a clean code base. It's not critical at all, but it's an easy patch, and clean and simple code always roxx :)

Fabianx’s picture

Issue tags: -Performance

function system_cron() {
   /* ... */
  $core = array('cache', 'cache_block', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
  foreach ($cache_tables as $table) {
    cache_clear_all(NULL, $table);
  }
}

EDIT: This of course (as pointed out by crea below) only clears expired items and not the whole cache.

cache_clear_all with empty 'cid' will only clear expired items.

Back to topic:

Anyone up to make a patch for review? Then we can persuade the maintainer to commit this :-).

Best Wishes,

Fabian

pounard’s picture

True! If I have enough motivation I'd do one tonight :)

crea’s picture

@Fabianx System_cron() expires old items, and strongarm explicitly clears variable cache. There's big difference. See cache_clear_all() function signature.

Fabianx’s picture

Issue tags: +Performance

@crea You are absolutely right, the cache_clear_all function is a little confusing in its usage. I'll update my post.

Yep, clearing variables cache each time has a huge performance impact.

Best Wishes,

Fabian

PS: Added Performance tag.

pounard’s picture

Patch for 6.x-2.x.
Why is it important to clear variable cache on module page? Does it fix some kind of bug? If so, take the first patch, if not, take the second.

pounard’s picture

Same comment for D7 version.

pounard’s picture

Sorry, forgot one function call.

EDIT: These are the good one. The forgotten line only affects admin pages.

crea’s picture

I suspect motivation for implementing hook_flush_caches() was to react on global cache clear event, cause it's the only way to do that without hacking core.

Fabianx’s picture

So, I took a look at the "git annotate log" to find out the history of these changes.

Here is some more information on the issue.

* strongarm_flush_caches was implemented intentionally (it seems).

* strongarm_flush_caches was first called strongarm_invalidate_cache().

* This was changed in fc10987f by yhahn with comment of: #533354: Implement "weakarm"'ing of variables: Implement weakarm mode for strongarm.

Before it was only clearing the strongarm cache, now it also clears the variables cache:

Excerpt of diff:

 /**
- * Invalidates the strongarm cache.
+ * Implementation of hook_flush_caches().
  */
-function strongarm_invalidate_cache() {
+function strongarm_flush_caches() {
+  cache_clear_all('variables', 'cache');
   cache_clear_all('strongarm', 'cache');
 }

EDIT: Hm, nope, hook_flush_caches was there before, but it was just calling strongarm_invalidate_cache.

OKAY: The hook_flush_caches was already there in the initial commit of strongarm module, so we get no explanation whatsforever for this.

Here also a first attempt was made to clear the strongarm cache:

+  // Clear strongarm & variable caches on modules page.
+  if ($form_id == 'system_module') {
+    strongarm_flush_caches();
   }

Later this was just re-engineered to use the system_module_alter call we now have.

Not really much, I know, but perhaps the above linked issue explains more.

EDIT: It does not, but I think yhahn just took over the old decisions the code had made from beginning on and just extended it ...

Best Wishes,

Fabian

pounard’s picture

strongarm_flush_caches was first called strongarm_invalidate_cache().

If this function is really useful, then it was a better name (at least not conflicting with a hook doing the exact same thing).

This was changed in fc10987f by yhahn with comment of: #533354: Implement weakarm mode for strongarm.

This path is really a big patch, errors can be in.

This is pretty good historical explanation, but I still don't see the point of keeping that. Seems to be a design error that has been kept from the very beginning without never being questioned.

Fabianx’s picture

I suspect motivation for implementing hook_flush_caches() was to react on global cache clear event, cause it's the only way to do that without hacking core.

This could well be, but would not make any sense with just clearing "strongarm" cid. (which was in the original patch).

I do agree with pounard that this has slipped in accidentally and been dragged along from the start and is not needed, but has never been challenged before.

Best Wishes,

Fabian

tirdadc’s picture

Assigned: Unassigned » tirdadc

Thanks for investigating this. I need to find out a bit more about why certain things were done that way, but I'll definitely keep this fix in mind.

kenorb’s picture

Assigned: tirdadc » Unassigned
Issue summary: View changes
Status: Active » Closed (outdated)

Closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.