Problem/Motivation
Some cache backends including the database implementation rely on serialization to store cached data:
// Unserialize and return the cached data.
if ($cache->serialized) {
$cache->data = unserialize($cache->data);
}
I had this situation where the container definition (that is by default stored in the database cache) could not be unserialized (there are several reasons that could lead to such a situation. I.e. a change in the environment/runtime can make something that could be previously unserialized not unserializable anymore).
In such a situation, the cache backend FAILS to provide reliable information, because it will return the stored data as FALSE (that is a completely valid cache data value).
The FALSE value propagates leading to a completely dead Drupal application:
[25-Apr-2017 15:13:32 Europe/Madrid] TypeError: Argument 1 passed to Drupal\Component\DependencyInjection\Container::__construct() must be of the type array, boolean given, called in D:\_Webs\chf_envivoui_FZd\app\web\core\lib\Drupal\Core\DrupalKernel.php on line 883 in D:\_Webs\chf_envivoui_FZd\app\web\core\lib\Drupal\Component\DependencyInjection\Container.php on line 119 #0 D:\_Webs\chf_envivoui_FZd\app\web\core\lib\Drupal\Core\DrupalKernel.php(883): Drupal\Component\DependencyInjection\Container->__construct(false)
#1 D:\_Webs\chf_envivoui_FZd\app\web\core\lib\Drupal\Core\DrupalKernel.php(461): Drupal\Core\DrupalKernel->initializeContainer()
#2 D:\_Webs\chf_envivoui_FZd\app\web\core\lib\Drupal\Core\DrupalKernel.php(651): Drupal\Core\DrupalKernel->boot()
#3 D:\_Webs\chf_envivoui_FZd\app\web\index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#4 {main}
Of course, in such a situation, a container rebuild will save they day. But I can imagine many other places where a corrupt serialized cache item could render the system unusable, and there would be no other solution but to completely wipe all caches - and there is no warranty that Drupal itself will be able to wipe the caches using regular mechanisms as it could be broken as in the previous situation - so you will need to do this in a more manual way.
Proposed resolution
When retrieving cache items using DatabaseCacheBackend, make sure that corrupt items are properly identified and treated as cache misses.
Currently broken items are treated as cache hits that return a FALSE as the cached data.
Remaining tasks
User interface changes
None.
API changes
None.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#37 | interdiff_18-37.txt | 6.87 KB | Prem Suthar |
#37 | 2872694-37.patch | 5.12 KB | Prem Suthar |
#18 | interdiff-15-17.txt | 1.51 KB | izaaksom |
#18 | database_backend_broken_when_corrupt_serialized_cache_2872694-17.patch | 2.49 KB | izaaksom |
Issue fork drupal-2872694
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
izaaksom CreditAttribution: izaaksom as a volunteer commentedHi, I'm really glad (?) that I'm not the only one having issues with this. There should be a normalized way in Drupal to handle caches and verify that when we return FALSE we are really a getting a FALSE and not corrupt data . Temporally I add a possible fix to this.
Comment #4
david_garcia CreditAttribution: david_garcia commentedExcelent patch! Not the most elegant approach, but does the job in a concise and cost-effective manner.
Time to update the issue summary.
Comment #5
catchThis could use some test coverage - for example inserting some data that can't be unserialized into a cache table directly, then retrieving it via the API.
Also there's some minor code style issues, like missing spaces before parenthesis/brackets. Could use a short explanatory comment as to why we're doing this as well.
unserialize() will issue an E_NOTICE when it can't unserialize data, so I think just the comparison above is fine and patch makes sense to me overall.
Comment #6
izaaksom CreditAttribution: izaaksom as a volunteer commentedHere is another patch that solves the code-style issues mentioned by catch on #5
Comment #7
david_garcia CreditAttribution: david_garcia commentedStyle issues seem to be fixed.
Comment #8
Wim LeersComment #9
izaaksom CreditAttribution: izaaksom as a volunteer commentedFixes #8
Comment #10
Wim LeersThanks!
Comment is wrong.
s/the corrupt object/a corrupt cache item/
s/object/cache item/
Please also post a failing test-only patch, so that we know that the new test coverage is indeed reproducing the original problem :)
(Post both a failing test-only patch and the patch in #9 in the same comment. Then it'll be very clear what patch you want a committer to commit.)
After that, this is RTBC!
Comment #11
Ada Hernandez CreditAttribution: Ada Hernandez at MTech, LLC commented#10 done
Comment #13
david_garcia CreditAttribution: david_garcia commentedComment #14
Wim LeersThanks!
Sorry, one last round of nits (which I think a committer would also raise):
s/a/the/
The method name is missing the "validator" bit.
This is the only place this is being used. This is a test. Let's just inline the
$this->container->get(…)
call.Comment #15
izaaksom CreditAttribution: izaaksom as a volunteer commentedFixes #14
Comment #16
Wim LeersThanks!
Comment #17
larowlanAn observation and a nit
We can combine these into a single if statement
nit - because they're both strings - we should use
!==
hereNice work here
nit: Can't we just use ''?
Comment #18
izaaksom CreditAttribution: izaaksom as a volunteer commentedFixes #17
Comment #19
dawehnerThere are many other places where we might have issues with serialize and we should have a look at? It might be worth looking at some followups ...
In an ideal world we would document on
CacheBackendInterface
that each backend ideally should have such a code ...Comment #20
david_garcia CreditAttribution: david_garcia commentedComment #21
david_garcia CreditAttribution: david_garcia commentedActually, every single call to unserialize() in Drupal's codebase should be revised to properly consider unserialization failure. I'd rather have a custom unserialize() that throws an exception upon failure, than having an "FALSE" being propagated as a successful result of unserialization.
Comment #22
catchWe shouldn't suppress the error from unserialize() with @ - that notice might be useful (for example if somehow a cache entry was always corrupted so never got successfully returned). So I'd remove that and just fix the return here.
Comment #25
bburgI am currently dealing with a site with a corrupt serialized value for the system.theme.data state. The site in question seems to run fine in production, but setting up in a VM for local development runs into this error, so there may be a local environment difference triggering this. But still, it seems like serialization/unserialization should be pretty straightforward.
It seems to happen with a long set of data, maybe it's trying to unserialize a multi-byte string? https://stackoverflow.com/questions/21072727/php-unserialize-strange-iss...
Comment #26
bburgFollow up from my last comment. It seemed that I was pulling a production database that was using a charset and collation for multi-byte strings. The live site is on Acquia, which uses these database settings: https://docs.acquia.com/acquia-cloud/manage/database/utf8mb4/.
So pulling the database to my local site, some serialized settings seemed to contain characters that are inappropraite for the normal utf8/latin1 encoding. When PHP tries to unserialize these stings, it just ends up with a false value.
Comment #36
larowlanComment #37
Prem Suthar CreditAttribution: Prem Suthar for Drupal India Association commentedRe-Rolled The patch For #18 As per the #35 Suggestion .Also add the Inter Diff For The #18 to #37.
Comment #38
Prem Suthar CreditAttribution: Prem Suthar for Drupal India Association commentedComment #39
smustgrave CreditAttribution: smustgrave commentedShould be MR.
DId not review
Comment #41
Prem Suthar CreditAttribution: Prem Suthar for Drupal India Association commentedComment #42
smustgrave CreditAttribution: smustgrave at Mobomo commentedMR still appears to have failures.
Comment #44
immaculatexavier CreditAttribution: immaculatexavier as a volunteer and at Material for Drupal India Association commentedFixed #41 , and created MR. Kindly review
Comment #45
smustgrave CreditAttribution: smustgrave at Mobomo commentedMR appears to have failures.