Over in #2966607: Invalidating 'node_list' and other broad cache tags early in a transaction severely increases lock wait time and probability of deadlock, discussion is being done regarding implementing a way to avoid deadlocks caused by invalidating cache tags. The same functionality will be needed on D7 to support the d8cache module.

Issue fork drupal-3004437

Command icon 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

bdragon created an issue. See original summary.

bdragon’s picture

StatusFileSize
new2.39 KB

Initial version of patch based on Fabian's idea.

bdragon’s picture

Initial testing of this patch is being done with #3004429: Invalidate cache tags after transaction.

bdragon’s picture

Status: Active » Needs review
bdragon’s picture

StatusFileSize
new4.97 KB

Updated patch to catch up with upstream.

More closely follow upstream patch.

Remove support for signaling on rollbacks.

It differs slightly from the D8 patch at the moment because it incorporates some future feedback that hasn't been posted to the D8 ticket yet.

fabianx’s picture

+++ b/includes/database/mysql/database.inc
@@ -180,9 +180,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
@@ -203,7 +201,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {

@@ -203,7 +201,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
             $this->transactionLayers = array();
             // We also have to explain to PDO that the transaction stack has
             // been cleaned-up.
-            PDO::commit();
+            $this->doCommit();
           }
           else {
             throw $e;

Is it a problem that now we can throw an Exception here -- while before this would not throw an Exception if the commit failed?

bdragon’s picture

StatusFileSize
new6.24 KB

Good point, making it do its own call to executeRootTransactionEndCallbacks() instead.

Patch updated again for readding the rollback root transaction calls. Additional call points identified.

fabianx’s picture

Title: [D7] Add ability to register rootEndTransaction callbacks during transactions. » [D7] [PP-D8] Add ability to register rootEndTransaction callbacks during transactions.
Status: Needs review » Reviewed & tested by the community
Issue tags: +Drupal 7.62 target

RTBC, but this needs to wait for the D8 issue to be in first.

joseph.olstad’s picture

mustanggb’s picture

Issue tags: -Drupal 7.64 target +Drupal 7.69 target
rosk0’s picture

Title: [D7] [PP-D8] Add ability to register rootEndTransaction callbacks during transactions. » [D7] Add ability to register rootEndTransaction callbacks during transactions.

D8 patch landed.

mustanggb’s picture

Issue tags: -Drupal 7.69 target +Drupal 7.70 target
poker10’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: -Drupal 7.70 target

After recent changes by #3185918: [PP-1] [PHP 8] Fix DatabaseConnection::query signature mismatch with PDO::query this patch no longer applies. It would need to be rerolled and checked.

ravi.shankar’s picture

Status: Needs work » Needs review
StatusFileSize
new6.17 KB
new5.55 KB

Added reroll of patch #7 on Drupal 7.x.

poker10’s picture

Status: Needs review » Needs work

Thanks for the reroll @ravi.shankar, but is seems like the test for PostgreSQL and SQLite are failing (problems accessing the parent::). It can be caused by the fact, that the DatabaseConnection class no longer extends PDO class after: #3185918: [PP-1] [PHP 8] Fix DatabaseConnection::query signature mismatch with PDO::query .

poker10’s picture

Assigned: bdragon » Unassigned
Status: Needs work » Needs review
StatusFileSize
new6.46 KB
new5.06 KB

I have updated the patch with some changes (see interdiff) and compared it to the current D9 code (some minor changes).

1 - Removed the Callable type-hinting, because it has been introduced only in PHP 5.4 (and D7 should support also PHP 5.3), so I think we can live without that.

2 - Changed the order of $this->connection->rollBack(); and $this->executeRootTransactionEndCallbacks(FALSE); functions in the SQLite driver (on multiple places) - this should be the correct order (the same is also in the D9 code).

3 - Fixed the doCommit() function (problem with ::parent, see the previous patch tests).

Let's check the testbot now.

torgospizza’s picture

There may be an issue in the patched code from this most recent patch, includes/database/mysql/database.inc in this block:

protected function doCommit() {
    if ($this->connection->inTransaction()) {
      $success = parent::doCommit();
    }
    else {
      // In PHP 8.0 a PDOException is thrown when a commit is attempted with no
      // transaction active. In previous PHP versions this failed silently.
      $success = TRUE;
      // Allow callbacks to perform their own cleanup.
      $this->executeRootTransactionEndCallbacks($success);
    }
    return $success;

Should DatabaseConnection::doCommit() return $success at the end? Without it, the child classes are testing for $success = parent::doCommit()) if in the middle of a transaction, but that parent function currently uses a void return value (due to there being no return statement).

+  /**
+   * Do the actual commit, invoke pre-commit callbacks.
+   *
+   * @internal
+   */
+  protected function doCommit() {
+    $success = $this->connection->commit();
+    $this->executeRootTransactionEndCallbacks($success);
+
+    if (!$success) {
+      throw new DatabaseTransactionCommitFailedException();
+    }
+  }
+
avpaderno’s picture

In DatabaseConnection, the patch adds this code.

+  /**
+   * Do the actual commit, invoke pre-commit callbacks.
+   *
+   * @internal
+   */
+  protected function doCommit() {
+    $success = $this->connection->commit();
+    $this->executeRootTransactionEndCallbacks($success);
+
+    if (!$success) {
+      throw new DatabaseTransactionCommitFailedException();
+    }
+  }

In DatabaseConnection_mysql, the code is changed as follows.

   protected function doCommit() {
     if ($this->connection->inTransaction()) {
-      return $this->connection->commit();
+      $success = parent::doCommit();
     }
     else {
       // In PHP 8.0 a PDOException is thrown when a commit is attempted with no
       // transaction active. In previous PHP versions this failed silently.
-      return TRUE;
+      $success = TRUE;
+      // Allow callbacks to perform their own cleanup.
+      $this->executeRootTransactionEndCallbacks($success);
     }
+    return $success;
   }

$success = parent::doCommit(); would just set $success to NULL, since DatabaseConnection::doCommit() does not return any value.

avpaderno’s picture

Title: [D7] Add ability to register rootEndTransaction callbacks during transactions. » [D7] Add ability to register rootEndTransaction callbacks during transactions

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.