The views output and result caches have giant data blobs. For example, turn on Time based cache for Recent Comments block and enable that block You will see that the results cache has full comment entities in it (including fields, ...). If you inspect the output cache, it has all of that plus a View object with lots more stuff.

Not that we have entity load cache, I would think we can just cache ids.

Comments

dawehner’s picture

Not that we have entity load cache, I would think we can just cache ids.

We have to cache basically the result coming from the DB which might be just entity IDs but could be arbitrary additional values.

We should though throw away the loaded entities and reload them on cache loading.

dawehner’s picture

StatusFileSize
new2.01 KB

We could do something like that.

damiankloip’s picture

Status: Active » Needs review
StatusFileSize
new1.95 KB
new991 bytes

Yes, I would be pretty happy with this approach. I think it would need to be like this instead though, so we don't assign the view result to NULL every time. But yeah, I guess it was just the idea there mainly.

It's a good point that we now should not really need to cache full entities. We will probably want to measure the performance difference here, with the additional queries needed 'n' all.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Ha

damiankloip’s picture

Title: Views results cache has full entities in it. Views output cache verbose as well. » Views results cache has full entities in it.

Also, re-titling/purposing. As making changes to the output cache will need alot more discussion, and is a much more complexed topic :)

The patch we have here is fine for the result cache.

damiankloip’s picture

Title: Views results cache has full entities in it. » Views results cache has full entities in it
Related issues: +#2158167: Views output cache is verbose
moshe weitzman’s picture

I tested this patch and the data is *much* briefer now. Thanks for the quick turnaround!

dries’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/cache/CachePluginBase.php
@@ -137,6 +137,25 @@ public function cacheSet($type) {
+      $clone = clone $row;
+      unset($clone->_entity, $clone->_relationship_entities);
+      $return[$key] = $clone;

Please add a comment explaining (1) what we are doing here and (2) why. It's not really clear from the phpDoc what 'preparing' means.

damiankloip’s picture

Status: Needs work » Needs review
StatusFileSize
new2.06 KB
new1.01 KB

hmm ok, That bit of code you've pasted seems pretty self explanatory to me tbh. The code is self descriptive (clone x, unset(x,y), assign). Did you also see the param docs? I think they complete the picture too:

   * @param \Drupal\views\ResultRow[] $result
   *   The result containing loaded entities.
   *
   * @return \Drupal\views\ResultRow[] $result
   *   The result without loaded entities.

Here is a comment to that effect anyway.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC.

catch’s picture

Status: Reviewed & tested by the community » Needs work

Hmm. Could we not load the entities after the cache_set()? Then it wouldn't be necessary to remove them from the cache entry and add them back. Thinking about other stuff than loaded entities which might get in here at some point.

I didn't look at how feasible that is, if the answer is 'not at the moment', then OK but could do with a follow-up.

damiankloip’s picture

I think that's a 'not at the moment' I'm afraid. cacheSet is called from ViewExecutable after query->execute() is called, it's in there that the rows are loaded, and loadEntities() is also called etc...

dawehner’s picture

Status: Needs work » Reviewed & tested by the community

I kind of like the fact that the query plugin is not aware of caching at the moment. The question on the other hand is whether the view executable should instead call the load entities method, as even only the query plugin will know exactly how to load them, it should not need to know when to load them.

This though is indeed more a follow up.

webchick’s picture

Assigned: Unassigned » catch

Back to catch!

catch’s picture

Assigned: catch » Unassigned

OK that's fair enough. Committed/pushed to 8.x, thanks!

damiankloip’s picture

Status: Reviewed & tested by the community » Fixed

Great. Thanks, and merry christmas, catch.

Status: Fixed » Closed (fixed)

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

damiankloip’s picture

Status: Closed (fixed) » Needs review
StatusFileSize
new2.04 KB

Reopening, looks like this never actually got committed :D

So here is a reroll. Good place to start.

dawehner’s picture

I kinda have the feeling we should test that we don't serialize the _entity components.

berdir’s picture

The entities themself are aren't even that much of a problem, they are pretty well optimized, although caching separately could result in cache inconsistencies if they are updated in the meantime. The biggest problem is really the ->view property, that serialized the whole view.

moshe weitzman’s picture

Status: Needs review » Needs work
Issue tags: +test, +Needs tests
damiankloip’s picture

Status: Needs work » Needs review
Issue tags: -test, -Needs tests
StatusFileSize
new1.85 KB
new3.9 KB

Quick test

The last submitted patch, 22: 2157777-22-tests-only-FAIL.patch, failed testing.

wim leers’s picture

Issue tags: +D8 cacheability
+++ b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -341,6 +343,29 @@ protected function getCacheTags() {
+      unset($clone->_entity, $clone->_relationship_entities);


+++ b/core/modules/views/src/Tests/Plugin/CacheTest.php
@@ -166,7 +166,37 @@ public function testSubqueryStringCache() {
+      $this->assertIdentical($row->_entity, NULL, 'Cached row "_entity" property is NULL');
+      $this->assertIdentical($row->_relationship_entities, [], 'Cached row "_relationship_entities" property is empty');

Evidently, this patch works, because it's green (unless $cache->data['result'] is empty, which you also may want to add a preventive assertion for, to prevent future regressions).

But how is it possible that the result of unset() is NULL in one case and the empty array in the other?

damiankloip’s picture

StatusFileSize
new4.08 KB
new776 bytes

Added an assertion that results are in the cache, that's a fair point.

But how is it possible that the result of unset() is NULL in one case and the empty array in the other?

This is possible because...serialization.

Try it:


$row = new \Drupal\views\ResultRow();
unset($row->_relationship_entities);
var_dump($row);
// Property gone.
var_dump(unserialize(serialize($row)));
// $_relationship_entities = array() again

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Oh, those are the defaults on ResultRow. Then that makes sense :)

Considering this was RTBC before, and that all that what was missing was more test coverage, I think this is now RTBC again.

damiankloip’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new4.79 KB
new1.35 KB

Talking to berdir on IRC, maybe we should set the values to their original instead of unsettings, but then, maybe we just add a method to call that does this for us.

EDIT: looks like x-post with WIm there. Wim, what do you think about this latest change? re-RTBC? :)

berdir’s picture

Status: Needs review » Reviewed & tested by the community

Interdiff looks good to me.

wim leers’s picture

Yep, trivial changes. RTBC+1

damiankloip’s picture

Thanks both.

catch’s picture

Committed/pushed to 8.0.x, thanks!

  • catch committed 47b7c00 on 8.0.x
    Issue #2157777 by damiankloip, dawehner: Views results cache has full...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

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