Merge "Special:Newpages feed now shows first revision instead of latest revision"
[lhc/web/wiklou.git] / includes / filebackend / lockmanager / MySqlLockManager.php
index 0536091..2108aed 100644 (file)
@@ -1,8 +1,16 @@
 <?php
+
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
+
 /**
  * MySQL version of DBLockManager that supports shared locks.
  *
- * All lock servers must have the innodb table defined in locking/filelocks.sql.
+ * Do NOT use this on connection handles that are also being used for anything
+ * else as the transaction isolation will be wrong and all the other changes will
+ * get rolled back when the locks release!
+ *
+ * All lock servers must have the innodb table defined in maintenance/locking/filelocks.sql.
  * All locks are non-blocking, which avoids deadlocks.
  *
  * @ingroup LockManager
@@ -15,9 +23,10 @@ class MySqlLockManager extends DBLockManager {
                self::LOCK_EX => self::LOCK_EX
        ];
 
-       protected function getLocalLB() {
-               // Use a separate connection so releaseAllLocks() doesn't rollback the main trx
-               return wfGetLBFactory()->newMainLB( $this->domain );
+       public function __construct( array $config ) {
+               parent::__construct( $config );
+
+               $this->session = substr( $this->session, 0, 31 ); // fit to field
        }
 
        protected function initConnection( $lockDb, IDatabase $db ) {
@@ -29,16 +38,16 @@ class MySqlLockManager extends DBLockManager {
 
        /**
         * Get a connection to a lock DB and acquire locks on $paths.
-        * This does not use GET_LOCK() per http://bugs.mysql.com/bug.php?id=1118.
+        * This does not use GET_LOCK() per https://bugs.mysql.com/bug.php?id=1118.
         *
         * @see DBLockManager::getLocksOnServer()
         * @param string $lockSrv
         * @param array $paths
         * @param string $type
-        * @return Status
+        * @return StatusValue
         */
        protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
 
                $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
 
@@ -51,7 +60,7 @@ class MySqlLockManager extends DBLockManager {
                        $keys[] = $key;
                        $data[] = [ 'fls_key' => $key, 'fls_session' => $this->session ];
                        if ( !isset( $this->locksHeld[$path][self::LOCK_EX] ) ) {
-                               $checkEXKeys[] = $key;
+                               $checkEXKeys[] = $key; // this has no EX lock on $key itself
                        }
                }
 
@@ -59,13 +68,16 @@ class MySqlLockManager extends DBLockManager {
                $db->insert( 'filelocks_shared', $data, __METHOD__, [ 'IGNORE' ] );
                # Actually do the locking queries...
                if ( $type == self::LOCK_SH ) { // reader locks
-                       $blocked = false;
                        # Bail if there are any existing writers...
                        if ( count( $checkEXKeys ) ) {
-                               $blocked = $db->selectField( 'filelocks_exclusive', '1',
+                               $blocked = $db->selectField(
+                                       'filelocks_exclusive',
+                                       '1',
                                        [ 'fle_key' => $checkEXKeys ],
                                        __METHOD__
                                );
+                       } else {
+                               $blocked = false;
                        }
                        # Other prospective writers that haven't yet updated filelocks_exclusive
                        # will recheck filelocks_shared after doing so and bail due to this entry.
@@ -74,7 +86,9 @@ class MySqlLockManager extends DBLockManager {
                        # Bail if there are any existing writers...
                        # This may detect readers, but the safe check for them is below.
                        # Note: if two writers come at the same time, both bail :)
-                       $blocked = $db->selectField( 'filelocks_shared', '1',
+                       $blocked = $db->selectField(
+                               'filelocks_shared',
+                               '1',
                                [ 'fls_key' => $keys, "fls_session != $encSession" ],
                                __METHOD__
                        );
@@ -87,7 +101,9 @@ class MySqlLockManager extends DBLockManager {
                                # Block new readers/writers...
                                $db->insert( 'filelocks_exclusive', $data, __METHOD__ );
                                # Bail if there are any existing readers...
-                               $blocked = $db->selectField( 'filelocks_shared', '1',
+                               $blocked = $db->selectField(
+                                       'filelocks_shared',
+                                       '1',
                                        [ 'fls_key' => $keys, "fls_session != $encSession" ],
                                        __METHOD__
                                );
@@ -105,10 +121,10 @@ class MySqlLockManager extends DBLockManager {
 
        /**
         * @see QuorumLockManager::releaseAllLocks()
-        * @return Status
+        * @return StatusValue
         */
        protected function releaseAllLocks() {
-               $status = Status::newGood();
+               $status = StatusValue::newGood();
 
                foreach ( $this->conns as $lockDb => $db ) {
                        if ( $db->trxLevel() ) { // in transaction