Merge "Improve docs for Title::getInternalURL/getCanonicalURL"
[lhc/web/wiklou.git] / includes / db / MWLBFactory.php
index a930b3b..bbb3d2f 100644 (file)
@@ -77,16 +77,27 @@ abstract class MWLBFactory {
                        'defaultGroup' => $mainConfig->get( 'DBDefaultGroup' ),
                ];
 
+               $serversCheck = [];
                // When making changes here, remember to also specify MediaWiki-specific options
                // for Database classes in the relevant Installer subclass.
                // Such as MysqlInstaller::openConnection and PostgresInstaller::openConnectionWithParams.
                if ( $lbConf['class'] === Wikimedia\Rdbms\LBFactorySimple::class ) {
+                       $httpMethod = $_SERVER['REQUEST_METHOD'] ?? null;
+                       // T93097: hint for how file-based databases (e.g. sqlite) should go about locking.
+                       // See https://www.sqlite.org/lang_transaction.html
+                       // See https://www.sqlite.org/lockingv3.html#shared_lock
+                       $isReadRequest = in_array( $httpMethod, [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
+
                        if ( isset( $lbConf['servers'] ) ) {
                                // Server array is already explicitly configured; leave alone
                        } elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
+                               $lbConf['servers'] = [];
                                foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
                                        if ( $server['type'] === 'sqlite' ) {
-                                               $server += [ 'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ) ];
+                                               $server += [
+                                                       'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ),
+                                                       'trxMode' => $isReadRequest ? 'DEFERRED' : 'IMMEDIATE'
+                                               ];
                                        } elseif ( $server['type'] === 'postgres' ) {
                                                $server += [
                                                        'port' => $mainConfig->get( 'DBport' ),
@@ -98,20 +109,6 @@ abstract class MWLBFactory {
                                                        'port' => $mainConfig->get( 'DBport' ),
                                                        'useWindowsAuth' => $mainConfig->get( 'DBWindowsAuthentication' )
                                                ];
-                                       } elseif ( $server['type'] === 'mysql' ) {
-                                               // A DB name is not needed to connect to mysql; 'dbname' is useless.
-                                               // This field only defines the DB to use for unspecified DB domains.
-                                               $ldDB = $mainConfig->get( 'DBname' ); // local domain DB
-                                               $srvDB = $server['dbname'] ?? null; // server DB
-                                               if ( $srvDB !== null && $srvDB !== $ldDB ) {
-                                                       self::reportMismatchedDBs( $srvDB, $ldDB );
-                                               }
-                                       }
-
-                                       $ldTP = $mainConfig->get( 'DBprefix' ); // local domain prefix
-                                       $srvTP = $server['tablePrefix'] ?? null; // server table prefix
-                                       if ( $srvTP !== '' && $srvTP !== $ldTP ) {
-                                               self::reportMismatchedPrefixes( $srvTP, $ldTP );
                                        }
 
                                        if ( in_array( $server['type'], $typesWithSchema, true ) ) {
@@ -122,7 +119,6 @@ abstract class MWLBFactory {
                                                'tablePrefix' => $mainConfig->get( 'DBprefix' ),
                                                'flags' => DBO_DEFAULT,
                                                'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                               'utf8Mode' => $mainConfig->get( 'DBmysql5' )
                                        ];
 
                                        $lbConf['servers'][$i] = $server;
@@ -142,7 +138,7 @@ abstract class MWLBFactory {
                                        'load' => 1,
                                        'flags' => $flags,
                                        'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                       'utf8Mode' => $mainConfig->get( 'DBmysql5' )
+                                       'trxMode' => $isReadRequest ? 'DEFERRED' : 'IMMEDIATE'
                                ];
                                if ( in_array( $server['type'], $typesWithSchema, true ) ) {
                                        $server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
@@ -162,16 +158,19 @@ abstract class MWLBFactory {
                        if ( !isset( $lbConf['externalClusters'] ) ) {
                                $lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
                        }
+
+                       $serversCheck = $lbConf['servers'];
                } elseif ( $lbConf['class'] === Wikimedia\Rdbms\LBFactoryMulti::class ) {
                        if ( isset( $lbConf['serverTemplate'] ) ) {
                                if ( in_array( $lbConf['serverTemplate']['type'], $typesWithSchema, true ) ) {
                                        $lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
                                }
                                $lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
-                               $lbConf['serverTemplate']['utf8Mode'] = $mainConfig->get( 'DBmysql5' );
                        }
+                       $serversCheck = $lbConf['serverTemplate'] ?? [];
                }
 
+               self::sanityCheckServerConfig( $serversCheck, $mainConfig );
                $lbConf = self::applyDefaultCaching( $lbConf, $srvCace, $mainStash, $wanCache );
 
                return $lbConf;
@@ -201,6 +200,50 @@ abstract class MWLBFactory {
                return $lbConf;
        }
 
+       /**
+        * @param array $servers
+        * @param Config $mainConfig
+        */
+       private static function sanityCheckServerConfig( array $servers, Config $mainConfig ) {
+               $ldDB = $mainConfig->get( 'DBname' ); // local domain DB
+               $ldTP = $mainConfig->get( 'DBprefix' ); // local domain prefix
+
+               foreach ( $servers as $server ) {
+                       $type = $server['type'] ?? null;
+                       $srvDB = $server['dbname'] ?? null; // server DB
+                       $srvTP = $server['tablePrefix'] ?? ''; // server table prefix
+
+                       if ( $type === 'mysql' ) {
+                               // A DB name is not needed to connect to mysql; 'dbname' is useless.
+                               // This field only defines the DB to use for unspecified DB domains.
+                               if ( $srvDB !== null && $srvDB !== $ldDB ) {
+                                       self::reportMismatchedDBs( $srvDB, $ldDB );
+                               }
+                       } elseif ( $type === 'postgres' ) {
+                               if ( $srvTP !== '' ) {
+                                       self::reportIfPrefixSet( $srvTP, $type );
+                               }
+                       }
+
+                       if ( $srvTP !== '' && $srvTP !== $ldTP ) {
+                               self::reportMismatchedPrefixes( $srvTP, $ldTP );
+                       }
+               }
+       }
+
+       /**
+        * @param string $prefix Table prefix
+        * @param string $dbType Database type
+        */
+       private static function reportIfPrefixSet( $prefix, $dbType ) {
+               $e = new UnexpectedValueException(
+                       "\$wgDBprefix is set to '$prefix' but the database type is '$dbType'. " .
+                       "MediaWiki does not support using a table prefix with this RDBMS type."
+               );
+               MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
+               exit;
+       }
+
        /**
         * @param string $srvDB Server config database
         * @param string $ldDB Local DB domain database
@@ -210,8 +253,8 @@ abstract class MWLBFactory {
                        "\$wgDBservers has dbname='$srvDB' but \$wgDBname='$ldDB'. " .
                        "Set \$wgDBname to the database used by this wiki project. " .
                        "There is rarely a need to set 'dbname' in \$wgDBservers. " .
-                       "Functions like wfWikiId(), remote wiki database access, the use " .
-                       "of Database::getDomainId(), and other features are not reliable when " .
+                       "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
+                       "use of Database::getDomainId(), and other features are not reliable when " .
                        "\$wgDBservers does not match the local wiki database/prefix."
                );
                MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
@@ -227,8 +270,8 @@ abstract class MWLBFactory {
                        "\$wgDBservers has tablePrefix='$srvTP' but \$wgDBprefix='$ldTP'. " .
                        "Set \$wgDBprefix to the table prefix used by this wiki project. " .
                        "There is rarely a need to set 'tablePrefix' in \$wgDBservers. " .
-                       "Functions like wfWikiId(), remote wiki database access, the use " .
-                       "of Database::getDomainId(), and other features are not reliable when " .
+                       "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
+                       "use of Database::getDomainId(), and other features are not reliable when " .
                        "\$wgDBservers does not match the local wiki database/prefix."
                );
                MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );