Merge "Cleaned up database reconnection logic"
[lhc/web/wiklou.git] / includes / db / Database.php
index b502bb9..16e1ef2 100644 (file)
@@ -806,7 +806,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
         * database. Example uses in core:
         * @see LoadBalancer::reallyOpenConnection()
         * @see ForeignDBRepo::getMasterDB()
-        * @see WebInstaller_DBConnect::execute()
+        * @see WebInstallerDBConnect::execute()
         *
         * @since 1.18
         *
@@ -926,7 +926,6 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                if ( count( $this->mTrxIdleCallbacks ) ) { // sanity
                        throw new MWException( "Transaction idle callbacks still pending." );
                }
-               $this->mOpened = false;
                if ( $this->mConn ) {
                        if ( $this->trxLevel() ) {
                                if ( !$this->mTrxAutomatic ) {
@@ -937,13 +936,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                                $this->commit( __METHOD__, 'flush' );
                        }
 
-                       $ret = $this->closeConnection();
+                       $closed = $this->closeConnection();
                        $this->mConn = false;
-
-                       return $ret;
                } else {
-                       return true;
+                       $closed = true;
                }
+               $this->mOpened = false;
+
+               return $closed;
        }
 
        /**
@@ -1054,7 +1054,8 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                # Keep track of whether the transaction has write queries pending
                if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) {
                        $this->mTrxDoneWrites = true;
-                       Profiler::instance()->transactionWritingIn( $this->mServer, $this->mDBname );
+                       $id = spl_object_hash( $this );
+                       Profiler::instance()->transactionWritingIn( $this->mServer, $this->mDBname, $id );
                }
 
                $queryProf = '';
@@ -1088,6 +1089,11 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
 
                $queryId = MWDebug::query( $sql, $fname, $isMaster );
 
+               # Avoid fatals if close() was called
+               if ( !$this->isOpen() ) {
+                       throw new DBUnexpectedError( $this, "DB connection was already closed." );
+               }
+
                # Do the query and handle errors
                $ret = $this->doQuery( $commentedSql );
 
@@ -1098,20 +1104,25 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        # Transaction is gone, like it or not
                        $hadTrx = $this->mTrxLevel; // possible lost transaction
                        $this->mTrxLevel = 0;
+                       $this->mTrxIdleCallbacks = array(); // bug 65263
+                       $this->mTrxPreCommitCallbacks = array(); // bug 65263
                        wfDebug( "Connection lost, reconnecting...\n" );
 
                        if ( $this->ping() ) {
+                               global $wgRequestTime;
                                wfDebug( "Reconnected\n" );
                                $sqlx = substr( $commentedSql, 0, 500 );
                                $sqlx = strtr( $sqlx, "\t\n", '  ' );
-                               global $wgRequestTime;
                                $elapsed = round( microtime( true ) - $wgRequestTime, 3 );
                                if ( $elapsed < 300 ) {
                                        # Not a database error to lose a transaction after a minute or two
                                        wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx" );
                                }
-                               if ( !$hadTrx ) {
-                                       # Should be safe to silently retry
+                               if ( $hadTrx ) {
+                                       # Leave $ret as false and let an error be reported.
+                                       # Callers may catch the exception and continue to use the DB.
+                               } else {
+                                       # Should be safe to silently retry (no trx and thus no callbacks)
                                        $ret = $this->doQuery( $commentedSql );
                                }
                        } else {
@@ -3405,11 +3416,17 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        $this->runOnTransactionPreCommitCallbacks();
                        $this->doCommit( $fname );
                        if ( $this->mTrxDoneWrites ) {
-                               Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+                               $id = spl_object_hash( $this );
+                               Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname, $id );
                        }
                        $this->runOnTransactionIdleCallbacks();
                }
 
+               # Avoid fatals if close() was called
+               if ( !$this->isOpen() ) {
+                       throw new DBUnexpectedError( $this, "DB connection was already closed." );
+               }
+
                $this->doBegin( $fname );
                $this->mTrxFname = $fname;
                $this->mTrxDoneWrites = false;
@@ -3468,10 +3485,16 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        }
                }
 
+               # Avoid fatals if close() was called
+               if ( !$this->isOpen() ) {
+                       throw new DBUnexpectedError( $this, "DB connection was already closed." );
+               }
+
                $this->runOnTransactionPreCommitCallbacks();
                $this->doCommit( $fname );
                if ( $this->mTrxDoneWrites ) {
-                       Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+                       $id = spl_object_hash( $this );
+                       Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname, $id );
                }
                $this->runOnTransactionIdleCallbacks();
        }
@@ -3517,12 +3540,18 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        }
                }
 
+               # Avoid fatals if close() was called
+               if ( !$this->isOpen() ) {
+                       throw new DBUnexpectedError( $this, "DB connection was already closed." );
+               }
+
                $this->doRollback( $fname );
                $this->mTrxIdleCallbacks = array(); // cancel
                $this->mTrxPreCommitCallbacks = array(); // cancel
                $this->mTrxAtomicLevels = new SplStack;
                if ( $this->mTrxDoneWrites ) {
-                       Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname );
+                       $id = spl_object_hash( $this );
+                       Profiler::instance()->transactionWritingOut( $this->mServer, $this->mDBname, $id );
                }
        }