Merge "GallerySlideshow: getImageInfo: Reject promise if there is no thumbnail"
[lhc/web/wiklou.git] / includes / filebackend / lockmanager / DBLockManager.php
index 2c86c37..c9aad43 100644 (file)
@@ -26,9 +26,8 @@
  *
  * This is meant for multi-wiki systems that may share files.
  *
- * All lock requests for a resource, identified by a hash string, will map
- * to one bucket. Each bucket maps to one or several peer DBs, each on their
- * own server, all having the filelocks.sql tables (with row-level locking).
+ * All lock requests for a resource, identified by a hash string, will map to one bucket.
+ * Each bucket maps to one or several peer DBs, each on their own server.
  * A majority of peer DBs must agree for a lock to be acquired.
  *
  * Caching is used to avoid hitting servers that are down.
@@ -37,7 +36,7 @@
  * @since 1.19
  */
 abstract class DBLockManager extends QuorumLockManager {
-       /** @var array Map of DB names to server config */
+       /** @var array[] Map of DB names to server config */
        protected $dbServers; // (DB name => server config array)
        /** @var BagOStuff */
        protected $statusCache;
@@ -46,8 +45,8 @@ abstract class DBLockManager extends QuorumLockManager {
        protected $safeDelay; // integer number of seconds
 
        protected $session = 0; // random integer
-       /** @var array Map Database connections (DB name => Database) */
-       protected $conns = array();
+       /** @var IDatabase[] Map Database connections (DB name => Database) */
+       protected $conns = [];
 
        /**
         * Construct a new instance from configuration.
@@ -76,7 +75,7 @@ abstract class DBLockManager extends QuorumLockManager {
 
                $this->dbServers = isset( $config['dbServers'] )
                        ? $config['dbServers']
-                       : array(); // likely just using 'localDBMaster'
+                       : []; // likely just using 'localDBMaster'
                // Sanitize srvsByBucket config to prevent PHP errors
                $this->srvsByBucket = array_filter( $config['dbsByBucket'], 'is_array' );
                $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive
@@ -113,6 +112,8 @@ abstract class DBLockManager extends QuorumLockManager {
                return $status;
        }
 
+       abstract protected function doGetLocksOnServer( $lockSrv, array $paths, $type );
+
        protected function freeLocksOnServer( $lockSrv, array $pathsByType ) {
                return Status::newGood();
        }
@@ -148,8 +149,7 @@ abstract class DBLockManager extends QuorumLockManager {
                if ( !isset( $this->conns[$lockDb] ) ) {
                        $db = null;
                        if ( $lockDb === 'localDBMaster' ) {
-                               $lb = wfGetLBFactory()->getMainLB( $this->domain );
-                               $db = $lb->getConnection( DB_MASTER, array(), $this->domain );
+                               $db = $this->getLocalLB()->getConnection( DB_MASTER, [], $this->domain );
                        } elseif ( isset( $this->dbServers[$lockDb] ) ) {
                                $config = $this->dbServers[$lockDb];
                                $db = DatabaseBase::factory( $config['type'], $config );
@@ -162,7 +162,7 @@ abstract class DBLockManager extends QuorumLockManager {
                        # If the connection drops, try to avoid letting the DB rollback
                        # and release the locks before the file operations are finished.
                        # This won't handle the case of DB server restarts however.
-                       $options = array();
+                       $options = [];
                        if ( $this->lockExpiry > 0 ) {
                                $options['connTimeout'] = $this->lockExpiry;
                        }
@@ -176,6 +176,13 @@ abstract class DBLockManager extends QuorumLockManager {
                return $this->conns[$lockDb];
        }
 
+       /**
+        * @return LoadBalancer
+        */
+       protected function getLocalLB() {
+               return wfGetLBFactory()->getMainLB( $this->domain );
+       }
+
        /**
         * Do additional initialization for new lock DB connection
         *
@@ -235,22 +242,25 @@ abstract class DBLockManager extends QuorumLockManager {
 
 /**
  * MySQL version of DBLockManager that supports shared locks.
+ *
+ * All lock servers must have the innodb table defined in locking/filelocks.sql.
  * All locks are non-blocking, which avoids deadlocks.
  *
  * @ingroup LockManager
  */
 class MySqlLockManager extends DBLockManager {
        /** @var array Mapping of lock types to the type actually used */
-       protected $lockTypeMap = array(
+       protected $lockTypeMap = [
                self::LOCK_SH => self::LOCK_SH,
                self::LOCK_UW => self::LOCK_SH,
                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 );
+       }
 
-       /**
-        * @param string $lockDb
-        * @param IDatabase $db
-        */
        protected function initConnection( $lockDb, IDatabase $db ) {
                # Let this transaction see lock rows from other transactions
                $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;" );
@@ -271,28 +281,28 @@ class MySqlLockManager extends DBLockManager {
 
                $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
 
-               $keys = array(); // list of hash keys for the paths
-               $data = array(); // list of rows to insert
-               $checkEXKeys = array(); // list of hash keys that this has no EX lock on
+               $keys = []; // list of hash keys for the paths
+               $data = []; // list of rows to insert
+               $checkEXKeys = []; // list of hash keys that this has no EX lock on
                # Build up values for INSERT clause
                foreach ( $paths as $path ) {
                        $key = $this->sha1Base36Absolute( $path );
                        $keys[] = $key;
-                       $data[] = array( 'fls_key' => $key, 'fls_session' => $this->session );
+                       $data[] = [ 'fls_key' => $key, 'fls_session' => $this->session ];
                        if ( !isset( $this->locksHeld[$path][self::LOCK_EX] ) ) {
                                $checkEXKeys[] = $key;
                        }
                }
 
                # Block new writers (both EX and SH locks leave entries here)...
-               $db->insert( 'filelocks_shared', $data, __METHOD__, array( 'IGNORE' ) );
+               $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',
-                                       array( 'fle_key' => $checkEXKeys ),
+                                       [ 'fle_key' => $checkEXKeys ],
                                        __METHOD__
                                );
                        }
@@ -304,20 +314,20 @@ class MySqlLockManager extends DBLockManager {
                        # 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',
-                               array( 'fls_key' => $keys, "fls_session != $encSession" ),
+                               [ 'fls_key' => $keys, "fls_session != $encSession" ],
                                __METHOD__
                        );
                        if ( !$blocked ) {
                                # Build up values for INSERT clause
-                               $data = array();
+                               $data = [];
                                foreach ( $keys as $key ) {
-                                       $data[] = array( 'fle_key' => $key );
+                                       $data[] = [ 'fle_key' => $key ];
                                }
                                # Block new readers/writers...
                                $db->insert( 'filelocks_exclusive', $data, __METHOD__ );
                                # Bail if there are any existing readers...
                                $blocked = $db->selectField( 'filelocks_shared', '1',
-                                       array( 'fls_key' => $keys, "fls_session != $encSession" ),
+                                       [ 'fls_key' => $keys, "fls_session != $encSession" ],
                                        __METHOD__
                                );
                        }
@@ -361,11 +371,11 @@ class MySqlLockManager extends DBLockManager {
  */
 class PostgreSqlLockManager extends DBLockManager {
        /** @var array Mapping of lock types to the type actually used */
-       protected $lockTypeMap = array(
+       protected $lockTypeMap = [
                self::LOCK_SH => self::LOCK_SH,
                self::LOCK_UW => self::LOCK_SH,
                self::LOCK_EX => self::LOCK_EX
-       );
+       ];
 
        protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
                $status = Status::newGood();
@@ -376,13 +386,13 @@ class PostgreSqlLockManager extends DBLockManager {
                $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
                $bigints = array_unique( array_map(
                        function ( $key ) {
-                               return wfBaseConvert( substr( $key, 0, 15 ), 16, 10 );
+                               return Wikimedia\base_convert( substr( $key, 0, 15 ), 16, 10 );
                        },
-                       array_map( array( $this, 'sha1Base16Absolute' ), $paths )
+                       array_map( [ $this, 'sha1Base16Absolute' ], $paths )
                ) );
 
                // Try to acquire all the locks...
-               $fields = array();
+               $fields = [];
                foreach ( $bigints as $bigint ) {
                        $fields[] = ( $type == self::LOCK_SH )
                                ? "pg_try_advisory_lock_shared({$db->addQuotes( $bigint )}) AS K$bigint"
@@ -393,7 +403,7 @@ class PostgreSqlLockManager extends DBLockManager {
 
                if ( in_array( 'f', $row ) ) {
                        // Release any acquired locks if some could not be acquired...
-                       $fields = array();
+                       $fields = [];
                        foreach ( $row as $kbigint => $ok ) {
                                if ( $ok === 't' ) { // locked
                                        $bigint = substr( $kbigint, 1 ); // strip off the "K"