Merge "Do not auto-reconnect to DBs if named locks where lost"
[lhc/web/wiklou.git] / includes / db / Database.php
index 37c9d6f..a4d0ad0 100644 (file)
@@ -141,6 +141,13 @@ abstract class DatabaseBase implements IDatabase {
         */
        private $mTrxAutomaticAtomic = false;
 
+       /**
+        * Track the write query callers of the current transaction
+        *
+        * @var string[]
+        */
+       private $mTrxWriteCallers = array();
+
        /**
         * Track the seconds spent in write queries for the current transaction
         *
@@ -148,6 +155,9 @@ abstract class DatabaseBase implements IDatabase {
         */
        private $mTrxWriteDuration = 0.0;
 
+       /** @var array Map of (name => 1) for locks obtained via lock() */
+       private $mNamedLocksHeld = array();
+
        /** @var IDatabase|null Lazy handle to the master DB this server replicates from */
        private $lazyMasterHandle;
 
@@ -282,9 +292,19 @@ abstract class DatabaseBase implements IDatabase {
         * @return TransactionProfiler
         */
        protected function getTransactionProfiler() {
-               return $this->trxProfiler
-                       ? $this->trxProfiler
-                       : Profiler::instance()->getTransactionProfiler();
+               if ( !$this->trxProfiler ) {
+                       $this->trxProfiler = new TransactionProfiler();
+               }
+
+               return $this->trxProfiler;
+       }
+
+       /**
+        * @param TransactionProfiler $profiler
+        * @since 1.27
+        */
+       public function setTransactionProfiler( TransactionProfiler $profiler ) {
+               $this->trxProfiler = $profiler;
        }
 
        /**
@@ -377,6 +397,10 @@ abstract class DatabaseBase implements IDatabase {
                return $this->mTrxLevel ? $this->mTrxWriteDuration : false;
        }
 
+       public function pendingWriteCallers() {
+               return $this->mTrxLevel ? $this->mTrxWriteCallers : array();
+       }
+
        public function isOpen() {
                return $this->mOpened;
        }
@@ -850,7 +874,7 @@ abstract class DatabaseBase implements IDatabase {
                                $msg = __METHOD__ . ": lost connection to $server; reconnected";
                                wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
 
-                               if ( $hadTrx ) {
+                               if ( $hadTrx || $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 );
@@ -881,6 +905,7 @@ abstract class DatabaseBase implements IDatabase {
 
                if ( $isWriteQuery && $this->mTrxLevel ) {
                        $this->mTrxWriteDuration += $queryRuntime;
+                       $this->mTrxWriteCallers[] = $fname;
                }
 
                return $res;
@@ -2600,6 +2625,7 @@ abstract class DatabaseBase implements IDatabase {
                $this->mTrxPreCommitCallbacks = array();
                $this->mTrxShortId = wfRandomString( 12 );
                $this->mTrxWriteDuration = 0.0;
+               $this->mTrxWriteCallers = array();
                // First SELECT after BEGIN will establish the snapshot in REPEATABLE-READ.
                // Get an estimate of the slave lag before then, treating estimate staleness
                // as lag itself just to be safe
@@ -2675,14 +2701,10 @@ abstract class DatabaseBase implements IDatabase {
                        if ( !$this->mTrxLevel ) {
                                wfWarn( "$fname: No transaction to rollback, something got out of sync!" );
                                return; // nothing to do
-                       } elseif ( $this->mTrxAutomatic ) {
-                               wfWarn( "$fname: Explicit rollback of implicit transaction. Something may be out of sync!" );
                        }
                } else {
                        if ( !$this->mTrxLevel ) {
                                return; // nothing to do
-                       } elseif ( !$this->mTrxAutomatic ) {
-                               wfWarn( "$fname: Flushing an explicit transaction, getting out of sync!" );
                        }
                }
 
@@ -3141,13 +3163,33 @@ abstract class DatabaseBase implements IDatabase {
        }
 
        public function lock( $lockName, $method, $timeout = 5 ) {
+               $this->mNamedLocksHeld[$lockName] = 1;
+
                return true;
        }
 
        public function unlock( $lockName, $method ) {
+               unset( $this->mNamedLocksHeld[$lockName] );
+
                return true;
        }
 
+       public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+               if ( !$this->lock( $lockKey, $fname, $timeout ) ) {
+                       return null;
+               }
+
+               $that = $this;
+               $unlocker = new ScopedCallback( function () use ( $that, $lockKey, $fname ) {
+                       $that->commit( __METHOD__, 'flush' );
+                       $that->unlock( $lockKey, $fname );
+               } );
+
+               $this->commit( __METHOD__, 'flush' );
+
+               return $unlocker;
+       }
+
        public function namedLocksEnqueue() {
                return false;
        }