Problem/Motivation

There are many cases where running the database updates can be problematic with warm caches. #3052971: Notice: Undefined index: #include_fallback in Drupal\Core\Render\Element\StatusMessages::generatePlaceholder() is just a very recent example.

Proposed resolution

Decorate the cache_factory with a special update cache factory that uses a NullBackend based backend. The special update backend passes on deletes to the real backend so cache flushes occur as expected so once updates are not being done the caches are empty as expected.

Maybe a better fix would be to somehow swap back to the unmodified container - ie. one without UpdateServiceProvider prior to calling drupal_flush_all_caches(). The problemswith this are:

  • How to determine this in UpdateKernel - use a query parameter?
  • drupal_flush_all_caches() does a container rebuild so we’re going to end up with multiples of these.

Remaining tasks

Discuss/review.

User interface changes

Nope.

API changes

TBD.

Data model changes

Nope.

Release notes snippet

Caches are no longer used during Drupal's update process. They are only cleared.

CommentFileSizeAuthor
#44 3055443-2-44.patch7.9 KBalexpott
#44 37-44-interdiff.txt1.15 KBalexpott
#37 3055443-2-37.patch7.88 KBalexpott
#37 36-37-interdiff.txt5.75 KBalexpott
#36 3055443-2-36.patch13.63 KBalexpott
#36 3055443-2-test-36.patch12.91 KBalexpott
#36 32-36-interdiff.txt8.05 KBalexpott
#35 3055443-contact-test.txt2.01 KBcatch
#32 3055443-2-32.patch19.06 KBalexpott
#32 23-32-interdiff.txt7.8 KBalexpott
#32 3055443-2-will-fail-32.patch12.99 KBalexpott
#32 32-32-will-fail-interdiff.txt499 bytesalexpott
#31 3055443-2-31.patch13.87 KBalexpott
#31 30-31-interdiff.txt2.25 KBalexpott
#30 3055443-2-30.patch12.92 KBalexpott
#30 23-30-interdiff.txt903 bytesalexpott
#23 3055443-23.patch12.5 KBalexpott
#23 21-23-interdiff.txt4.27 KBalexpott
#21 3055443-21.patch11.96 KBalexpott
#20 3055443-20.patch11.75 KBalexpott
#20 19-20-interdiff.txt907 bytesalexpott
#19 3055443-19.patch11.63 KBalexpott
#19 17-19-interdiff.txt2.3 KBalexpott
#17 3055443-17.patch11.63 KBalexpott
#17 16-17-interdiff.txt3.35 KBalexpott
#16 3055443-16.patch9.92 KBalexpott
#16 14-16-interdiff.txt2.47 KBalexpott
#14 3055443-14.patch12.38 KBalexpott
#14 11-14-interdiff.txt9.03 KBalexpott
#11 3055443-11.patch5.82 KBalexpott
#2 3055443.patch692 bytesamateescu
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

amateescu created an issue. See original summary.

amateescu’s picture

Status: Active » Needs review
FileSize
692 bytes

This should do it.

catch’s picture

So if we do this I think we should only clear out the cache bins (this logic copied from drupal_flush_all_caches() rather than doing a full rebuild to minimise the code path.

  foreach (Cache::getBins() as $service_id => $cache_backend) {
    $cache_backend->deleteAll();
  }

Status: Needs review » Needs work

The last submitted patch, 2: 3055443.patch, failed testing. View results

alexpott’s picture

Another thought is that we should not be write or reading anything from caches until update.php is done with.

alexpott’s picture

Also putting it in the batch is too late - #3052971: Notice: Undefined index: #include_fallback in Drupal\Core\Render\Element\StatusMessages::generatePlaceholder() occurs when the user visits update.php

alexpott’s picture

I think whatever we do should potentially be in \Drupal\Core\Update\UpdateServiceProvider

Berdir’s picture

There's an issue that aims to use memory cache backends for the installer, could we do the same for update? However, just like in the installer is that at the end, we do want to clear the real caches.

alexpott’s picture

@Berdir +1 to the memory cache idea. At least means we don't spend unnecessary resources working things out twice.

alexpott’s picture

alexpott’s picture

Version: 8.7.x-dev » 8.8.x-dev
Status: Needs work » Needs review
FileSize
5.82 KB

Let's see what breaks - gonna add some proper testing to ensure the cache is cleared by an update.

Status: Needs review » Needs work

The last submitted patch, 11: 3055443-11.patch, failed testing. View results

alexpott’s picture

Title: Clear all caches before running the database updates » Switch to a memory backend for running the database updates
alexpott’s picture

Status: Needs work » Needs review
FileSize
9.03 KB
12.38 KB
alexpott’s picture

Issue summary: View changes
alexpott’s picture

The change to core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php is no longer necessary now we're passing deletes on to the real cache backend.

alexpott’s picture

@catch asked for some comments about why we have the changes to the cache classes.

oknate’s picture

1) s/serialised/serialized
Content style guide specifies American spelling, and it's used with American spelling on core.

diff --git a/core/lib/Drupal/Core/Cache/MemoryCache/MemoryCache.php b/core/lib/Drupal/Core/Cache/MemoryCache/MemoryCache.php
index 3271108211..c6fa20ba98 100644
--- a/core/lib/Drupal/Core/Cache/MemoryCache/MemoryCache.php
+++ b/core/lib/Drupal/Core/Cache/MemoryCache/MemoryCache.php
@@ -8,40 +8,29 @@
 /**
  * Defines a memory cache implementation.
  *
- * Stores cache items in memory using a PHP array.
+ * Stores cache items in memory using a PHP array. Cache data is not serialised
+ * thereby returning the same object as was cached.

2) same for s/minimise/minimize
3) same for s/whilst/while

alexpott’s picture

Indeed - thanks @oknate!

alexpott’s picture

Resolved the @todo and added a change record.

alexpott’s picture

catch’s picture

Just nits. Looks really good to me now otherwise.

  1. +++ b/core/lib/Drupal/Core/Update/UpdateBackend.php
    @@ -0,0 +1,50 @@
    + * uses anything cached prior to running updates.
    

    using

  2. +++ b/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php
    @@ -0,0 +1,35 @@
    + * Decorates the real cache factory to use the special UpdateBackend.
    

    This should probably be either actual English or the fully qualified class name.

alexpott’s picture

@catch thanks for the review. I re-read all the things and found some missing properties and copy pasta. I decided to drop the "real" from the names of things because it's not helpful and replaced with "regular runtime" which I think is more indicative of what I meant by "real".

chr.fritsch’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me. We are already using this patch for our Thunder 2 -> 3 update path and it works very well.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed c22202e and pushed to 8.8.x. Thanks!

  • catch committed c22202e on 8.8.x
    Issue #3055443 by alexpott, amateescu, catch, Berdir, chr.fritsch:...
alexpott’s picture

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

I think we should consider backporting to this to 8.7.x.

  • It fixes problems with updating from contrib media_entity to core media - which is something we want people to do.
  • It fixes problems caused by extension serialisation that have mostly been fixed but can still occur under some circumstances.

Also whilst this change is big

  • it is to the update path caching and basically makes everyones updates behave in the way we actually test them.
  • it is only to the update system which doesn't affect the regular run-time of a site.
alexpott’s picture

Version: 8.7.x-dev » 8.8.x-dev
Status: Reviewed & tested by the community » Needs work

Unfortunately we need to revert this as it is causing random fails for SQLite. Not sure why yet. See https://www.drupal.org/pift-ci-job/1353542 for an example fail.

  • alexpott committed 6db9da0 on 8.8.x
    Revert "Issue #3055443 by alexpott, amateescu, catch, Berdir, chr....
alexpott’s picture

Status: Needs work » Needs review
FileSize
903 bytes
12.92 KB

So this patch fixes the random fail. I've not worked out why it's happening yet.

alexpott’s picture

Okay worked this out :( it's because system_update_8013() does not account for the container rebuild :( :( :(

This happens for all db types it just happens that SQLite does updates fast enough sometimes for system_update_8013() and system_update_8200() to run in the same batch.

Whilst the patch attached fixes the problem I'm not 100% sure it is the correct solution. The reason nothing goes wrong in HEAD is that none of the protected properties on the stale config factory are re-used during the save after the container rebuild. I think the correct solution might be do use a static property in

alexpott’s picture

So here's the fix I think we should do. We need to make the UpdateBackend caches survive a container rebuild so they behave more like a consistent cache like DatabaseBackend. Therefore we need to use statics.

All the interdiffs are back to #23 - I include a simple fail patch that fails with a very small addition to #23 to show the problem. This fails regardless of DB backend.

alexpott’s picture

I wonder if I should put the static stuff into it's own backend because I suspect it would safer to use in #2488350: Switch to a memory cache backend during installation too. Install has plenty of container rebuilds going on.

The last submitted patch, 32: 3055443-2-will-fail-32.patch, failed testing. View results

catch’s picture

FileSize
2.01 KB

This seems like a problem with the contact test to me - i.e. the test runner is using a stale version of the container.
Same problem as in #2066993: Use \Drupal consistently in tests. See diff for a suggestion.

alexpott’s picture

Discuss a bit more with @catch. We ruled out #32 because statics have their own level of problems and while it does it the UpdateBackend more like the DatabaseBackend @catch favoured another solution. We can extend the NullBackend instead and not actually cache anything!

I include a test patch which adds test code to system_udpate_8013() to prove we have it fixed.
The "real" patch here fixes system_udpate_8013() so that core sets a good example for contrib and custom to follow.

alexpott’s picture

Now we're extending from NullBackend there's no need to fix the MemoryBackend or MemoryCache classes.

alexpott’s picture

The improvements to MemoryBackend and MemoryCache can be a part of #2488350: Switch to a memory cache backend during installation - which is where they came from originally.

chr.fritsch’s picture

We need a title and an IS update here since we are no longer switching to the memory backend.

alexpott’s picture

Title: Switch to a memory backend for running the database updates » Switch to a null backend for all caches for running the database updates
Issue summary: View changes
Issue tags: -Needs issue summary update, -Needs title update

@chr.fritsch good point.

chr.fritsch’s picture

Status: Needs review » Reviewed & tested by the community

Looks good. We are already using this patch in Thunder for a while.

catch’s picture

+++ b/core/lib/Drupal/Core/Update/UpdateBackend.php
@@ -0,0 +1,54 @@
+ * Defines a cache backend for use during updating Drupal.

*during Drupal database updates

(fixable on commit).

Wim Leers’s picture

  1. +++ b/core/lib/Drupal/Core/Update/UpdateBackend.php
    @@ -0,0 +1,54 @@
    + * Passes on deletes to another backend while extending the NullBackend to avoid
    + * using anything cached prior to running updates.
    

    Woah! Super interesting 🤩

  2. +++ b/core/lib/Drupal/Core/Update/UpdateCacheBackendFactory.php
    @@ -0,0 +1,51 @@
    + * Cache factory implementation for updating Drupal.
    

    🤓 Nit: "to use when updating Drupal" would be more accurate I think?

  3. The change record's title and text still are talking about MemoryBackend, but this is now using a subclassed NullBackend.
alexpott’s picture

  • catch committed 80a307d on 8.8.x
    Issue #3055443 by alexpott, amateescu, catch, chr.fritsch, Berdir,...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed 80a307d and pushed to 8.8.x. Thanks!

Status: Fixed » Closed (fixed)

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

amateescu’s picture

This patch also fixed a nasty regression from 8.7.x: #3075675: Route cache can become poisoned with invalid data during database updates, resulting in 404s

I'm not sure if we need to backport the patch to that branch, but I thought it would be good to mention it at least.

liquidcms’s picture

I came across this: #2981353: The "media" entity type does not exist which led to this core issue. This seems to state that this fix was committed to 8.8.x 4 months ago yet I am running 8.8.1 which is only 1 month old.. and i am still getting this error when i try to do a db update.

liquidcms’s picture

i found another post suggesting to enable the (core) Media module - and this solved the issue.

quietone’s picture

Published the CR