Ignore noop DB transactions errors on connection loss
authorAaron Schulz <aschulz@wikimedia.org>
Sat, 20 Feb 2016 00:14:58 +0000 (16:14 -0800)
committerAaron Schulz <aschulz@wikimedia.org>
Wed, 24 Feb 2016 00:35:03 +0000 (00:35 +0000)
This avoids some needless exceptions for longer running scripts.

Bug: T127428
Change-Id: I3098141aa77a4c73cb2a0c784b38b15c712f82a9

includes/db/Database.php

index 351d438..02a6ec8 100644 (file)
@@ -859,8 +859,12 @@ abstract class DatabaseBase implements IDatabase {
 
                # Try reconnecting if the connection was lost
                if ( false === $ret && $this->wasErrorReissuable() ) {
-                       # Transaction is gone, like it or not
-                       $hadTrx = $this->mTrxLevel; // possible lost transaction
+                       # Transaction is gone; this can mean lost writes or REPEATABLE-READ snapshots
+                       $hadTrx = $this->mTrxLevel;
+                       # T127428: for non-write transactions, a disconnect and a COMMIT are similar:
+                       # neither changed data and in both cases any read snapshots are reset anyway.
+                       $isNoopCommit = ( !$this->writesOrCallbacksPending() && $sql === 'COMMIT' );
+                       # Update state tracking to reflect transaction loss
                        $this->mTrxLevel = 0;
                        $this->mTrxIdleCallbacks = []; // bug 65263
                        $this->mTrxPreCommitCallbacks = []; // bug 65263
@@ -874,12 +878,12 @@ abstract class DatabaseBase implements IDatabase {
                                $msg = __METHOD__ . ": lost connection to $server; reconnected";
                                wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
 
-                               if ( $hadTrx || $this->mNamedLocksHeld ) {
+                               if ( ( $hadTrx && !$isNoopCommit ) || $this->mNamedLocksHeld ) {
                                        # Leave $ret as false and let an error be reported.
                                        # Callers may catch the exception and continue to use the DB.
                                        $this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $tempIgnore );
                                } else {
-                                       # Should be safe to silently retry (no trx and thus no callbacks)
+                                       # Should be safe to silently retry (no trx/callbacks/locks)
                                        $startTime = microtime( true );
                                        $ret = $this->doQuery( $commentedSql );
                                        $queryRuntime = microtime( true ) - $startTime;