Problem/Motivation

There is a race condition when cache tables are recreated during a truncate. This causes exceptions to be thrown.

The original report

after upgrading to 8.6.12 from 8.6.10 seeing this error.
see screenshots

how to create.
click the "clear cache" button in admin/content/config

how to fix.
restart database server (mariadb on Fedora 25 linux)

recurrence
seems to be about every other day.

Proposed resolution

Catch a more generic exception if there are still problems the system will crash in other ways.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

N/a

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

starlightE created an issue. See original summary.

cilefen’s picture

I recommend putting the exception text in the issue summary so someone may find this. Contributors are busy and may not look at screenshots.

Also I recommend retitling this to “Cache clear occasionally throws” followed by a condensed bit of the exception message.

cilefen’s picture

The class containing ensureBinExists was last changed in December 2017.

I find it interesting that ensureBinExists tries to catch a SchemaObjectExistsException however Connection::handleQueryException will never produce a SchemaObjectExistsException.

The cache clearing codepath executes "TRUNCATE TABLE" on each cache table. "Truncate operations drop and re-create the table, which is much faster than deleting rows one by one, particularly for large tables", according to the MySQL docs.

So I think that ensureBinExists isn't performing as intended because it cannot catch the correct exception in the event another process has already created the table.

catch’s picture

Title: Clear Cache generates error in 8.6.12 » DatabaseCacheBackend::ensureBinExists() does not properly handle exceptions
Version: 8.6.x-dev » 8.8.x-dev
Priority: Normal » Major
Issue tags: +D8 cacheability, +Performance
dawehner’s picture

@catch
Thank you for finding the duplicated issue.
It seems there are two things we can do:

  • Try to be able to throw the exception by parsing the exception somehow. I would expect that this could be tricky to get right
  • We could catch all database exceptions when creating the cache bin (and potentially all the other lazy created tables).

I've implemented the second option as it seems to be pragmatic.

catch’s picture

Agreed with catching the less specific exception, it could potentially lead to silently not creating the table, but I cant really think of a situation where that would happen permanently and not affect anything else that would log/show an error.

johnwebdev’s picture

That seems like a work-around though...? Can we reproduce this in a test? We should handle this and not gracefully ignore it IMO. Lock mechanism seems more valid to me.

dawehner’s picture

That seems like a work-around though...? Can we reproduce this in a test? We should handle this and not gracefully ignore it IMO. Lock mechanism seems more valid to me.

it is really hard to write reliable/useful tests for race conditions. I can't think of a good one, but I might miss something.

alexpott’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update

I've discussed the solution with @dawehner and I agree with @catch that this seems like the best solution. I don't think we can use the lock system because the lock system is affected by this :)

I've checked that all code that does this on demand table creation is fixed and it appears to be. I think we should file a non-blocking follow-up to try to move some of this auto table creation logic to a trait.

alexpott’s picture

johnwebdev’s picture

it is really hard to write reliable/useful tests for race conditions. I can't think of a good one, but I might miss something.

Yeah, not sure. OWASP suggests black box testing. not sure if it's ever been done in Drupal, but it's definitely a interesting approach to see if more unexpected behaviour can be found by concurrency issues.

dawehner’s picture

@johndevman I'd be interested in seeing whether this is actually possible. That would be cool.

Wim Leers’s picture

We could write a test that manually throws the exception that should have been caught. Though that would again lead to a false sense of safety.

Given that, I think we can move forward with the current patch.

cilefen’s picture

Updating credit...

alexpott’s picture

Removing some unused uses.

FILE: ...s/drupal8alt.dev/core/lib/Drupal/Core/Config/DatabaseStorage.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 8 | WARNING | [x] Unused use statement
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 72ms; Memory: 8MB

PHPCS: core/lib/Drupal/Core/Flood/DatabaseBackend.php passed
PHPCS: core/lib/Drupal/Core/Lock/DatabaseLockBackend.php passed

FILE: ...tes/drupal8alt.dev/core/lib/Drupal/Core/Menu/MenuTreeStorage.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 14 | WARNING | [x] Unused use statement
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 172ms; Memory: 16MB

PHPCS: core/lib/Drupal/Core/Path/AliasStorage.php passed
PHPCS: core/lib/Drupal/Core/Queue/DatabaseQueue.php passed

FILE: ...es/drupal8alt.dev/core/lib/Drupal/Core/Routing/MatcherDumper.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 6 | WARNING | [x] Unused use statement
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 15: 3043907-15.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated Javascript test fail.

catch’s picture

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

Committed/pushed to 8.8.x and cherry-picked to 8.7.x, thanks!

  • catch committed 2bb3bba on 8.8.x
    Issue #3043907 by alexpott, dawehner, starlightE, cilefen:...

  • catch committed 142e826 on 8.7.x
    Issue #3043907 by alexpott, dawehner, starlightE, cilefen:...

Status: Fixed » Closed (fixed)

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