Problem/Motivation

Again quoting myself:

There doesn't seem to be any kind of static caching for this (e.g. in \Drupal\Core\Entity\ContentEntityBase::isLatestRevision or in the storage), but you can see that quickedit_preprocess_field() and quickedit_entity_view_alter() is calling it not just for each entity but again for each *field* being rendered for that entity. So we're not just doing this call once but maybe 10 times (or 30, if you have a lot of fields being displayed) on a site with quickedit enabled.

Additionally, I noticed that there are ~4 requests even without quickedit due to the local tasks access checking that goes through the \Drupal\Core\ParamConverter\EntityConverter::convert() and they all separately call that method.

Proposed resolution

Add static caching to getLatestTranslationAffectedRevisionId() and getLatestRevisionId()

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir created an issue. See original summary.

Berdir’s picture

Status: Active » Needs review
FileSize
2.73 KB

I'm expecting this to fail, e.g. in tests that save entities.

But, in my local testing, this saves about 12 queries. And it could be a lot more if you have more fields due to quickedit.

Status: Needs review » Needs work

The last submitted patch, 2: latest-revision-id-cache-2983887-2.patch, failed testing. View results

Berdir’s picture

This might fix the tests.

Status: Needs review » Needs work

The last submitted patch, 4: latest-revision-id-cache-2983887-4.patch, failed testing. View results

Berdir’s picture

And this fixes the remaining fails. Only two tests needed a manual cache clear, due to the usual form submissions and then checking in the test.

amateescu’s picture

Status: Needs review » Needs work

It seems that the patch from #2983837: Optimize EntityOperations::entityView() crept in here, let's remove it :)

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Workflow Initiative

This seems like a simple enough patch for a significant performance improvement.

Ideally we'd have profiling for concrete numbers, but saves 12 queries + #2950869: Entity queries querying the latest revision very slow with lots of revisions indicating that even a single execution of the query can be very slow means that this is guaranteed to aid performance significantly on sites with enough revisions :)

Sam152’s picture

It would be great to get #2934026: Deprecate isLatestRevision, getLatestRevision, getLatestRevisionId in the ModerationInformation service done after this, since the methods in ModerationInformation wont benefit from this static cache.

  • catch committed 8f00a9a on 8.7.x
    Issue #2983887 by Berdir: Add static cache to \Drupal\Core\Entity\...

  • catch committed e7862f1 on 8.6.x
    Issue #2983887 by Berdir: Add static cache to \Drupal\Core\Entity\...
catch’s picture

Version: 8.7.x-dev » 8.6.x-dev
Status: Reviewed & tested by the community » Fixed

Ideally we'd have profiling for concrete numbers, but saves 12 queries

Even for the fastest database query this would be worth doing so this doesn't really need profiling, slow queries generally only show up with lots of content.

Committed/pushed to 8.7.x and cherry-picked to 8.6.x. Thanks!

Wim Leers’s picture

Issue tags: +D8 cacheability

Status: Fixed » Closed (fixed)

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

tedbow’s picture

Just wanted to note that I had a test in #2937199: Track Layout override revisions on entities which support revisioning that was passing fail because of this change.

Basically I had to make sure i called $node_storage->resetCache([$revision_node->id()]); the second time I called $node_storage->getLatestRevisionId($revision_node->id()).

I am wondering if this could be a BC break because if a class gets the storage handler for an entity type \Drupal\Core\Entity\EntityTypeManager::getHandler() is going to give me an existing instance if another class has asked for the storage handler. So if another class called getLatestRevisionId() and then saved the entity. The next class that gets the storage handler will have to call resetCache() before the first time it calls getLatestRevisionId().

Is that correct?

Should we unset the latestRevisionIds in doPostSave()?

Berdir’s picture

You had to do that in a functional test, just like this issue had to in two instances.

Saving an entity already calls resetCache() and invalidates the revision ID for the same request. The problem with functional tests is that their in-memory caches can't get notified about changes done by web requests and get out of sync. We already invalidate a lot of static caches after every POST request but not everything.

That's a common problem for functional tests, 99% of the time that resetCache() is needed is inside tests.