This is a follow-up from #1055616: Query arguments should be replaced before generating cache ID

Display caches are missed unnecessarily.

Here is my analysis:
- After executing a cached display/view twiced, I find 1 results-record (which is OK), and 1 or 2 output-records (which is wrong) in table cache_views_data.

- after inserting a dpm() in function get_cache_key in views_plugin_cache.inc, or enabling the Devel Query log,
I find that the ['build_info']['...query']['arguments'] names are not consistent (but only for the results-cache). Mostly they are ':db_condition_placeholder_8 ' to ':db_condition_placeholder_11', but sometimes from 12-15 .

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Status: Active » Postponed

So this issue should be postponed for now.

johnv’s picture

Status: Postponed » Active

Not really, since it is discovered in that issue (which deals with caching and exposed filters), but it can happen with every cached view, so it is an independent issue.

johnv’s picture

If anyone could point me to the location where the ':db_condition_placeholder_' is generated, I am happy to test and create patch

Arnaud Meunier’s picture

johnv’s picture

@Arnaud,
Yes, your change in #1430650-39: Taxonomy filter with depth, Drupal 7.12, and views query caching failure resolves the issue.
I reported back in #1055616-84: Query arguments should be replaced before generating cache ID.
I saw you issue before, but never had the time to test that use case. Perhaps you can confirm if it is the case?

johnv’s picture

Status: Active » Closed (duplicate)
Fabianx’s picture

Title: Caches are missed, due to changing :db_condition_placeholder » :db_condition_placeholder leads to cache misses and superfluous cache_set
Priority: Normal » Major
Issue summary: View changes
Status: Closed (duplicate) » Active
Issue tags: +needs patch, +Novice

On the first call, the DB placeholders for the output cache are _16, _17, _18, etc.

On the second call, when the results cache is active, the placeholders are _1, _2, etc.

This leads to a cache miss on output cache on the second page load and an unreachable cached item.

The approach in #1430650: Taxonomy filter with depth, Drupal 7.12, and views query caching failure fixes it in theory, but relies on internal DB functionality.

A better approach is:

diff --git a/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc b/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
index 76bb4c66f..2a0b6b0e4 100644
--- a/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
+++ b/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
@@ -334,9 +334,14 @@ class views_plugin_cache extends views_plugin {
         if ($build_info[$index] instanceof SelectQueryInterface) {
           $query = clone $build_info[$index];
           $query->preExecute();
+
+          // Ensure that placeholders are always numerated from 0 to n.
+          $sql = (string) $query;
+          $arguments = (array) $query->getArguments();
+
+          $cache_arguments = array();
+          foreach (array_keys($arguments) as $key => $value) {
+            $cache_arguments[$value] = ':cache_placeholder_' . $key;
+          }
+
           $key_data['build_info'][$index] = array(
-            'sql' => (string) $query,
-            'arguments' => $query->getArguments(),
+            'sql' => strtr($sql, $cache_arguments),
+            'arguments' => array_values($arguments),
           );
         }
       }
Fabianx’s picture

Ohhhhh, I finally understand what is happening (after speaking with Earl about it!) and there is a better fix:

Pseudo-Code:

  $query = $build_info[$index];
  if (!$query->prepared()) {
    $query = clone $build_info[$index];
    $query->preExecute();
  }

should be all that is needed.

The reason why it works for results cache, but fails for output cache is because output cache is actually _after_ execution of the query, which is why the presence or absence of an already executed query makes it fail with different placeholders.

Fabianx’s picture

Status: Active » Needs review

It works!

diff --git a/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc b/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
index 76bb4c66f..67da0b9eb 100644
--- a/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
+++ b/docroot/sites/all/modules/contrib/views/plugins/views_plugin_cache.inc
@@ -332,8 +332,15 @@ class views_plugin_cache extends views_plugin {
         // If the default query back-end is used generate SQL query strings from
         // the query objects.
         if ($build_info[$index] instanceof SelectQueryInterface) {
-          $query = clone $build_info[$index];
-          $query->preExecute();
+          $query = $build_info[$index];
+
+          // If the query was not yet prepared, work on a clone and run
+          // preExecute().
+          if (!$query->isPrepared()) {
+            $query = clone $build_info[$index];
+            $query->preExecute();
+          }
+
           $key_data['build_info'][$index] = array(
             'sql' => (string) $query,
             'arguments' => $query->getArguments(),
Fabianx’s picture

And here is the patch.

DamienMcKenna’s picture

Excellent work, thank you Fabianx!

dawehner’s picture

This is indeed a nice fix!

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

This looks perfect from my point of view.

DamienMcKenna’s picture

Status: Reviewed & tested by the community » Fixed

Committed. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.