'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' ),
'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'] ?? ''; // server table prefix
- if ( $srvTP !== '' && $srvTP !== $ldTP ) {
- self::reportMismatchedPrefixes( $srvTP, $ldTP );
}
if ( in_array( $server['type'], $typesWithSchema, true ) ) {
'load' => 1,
'flags' => $flags,
'sqlMode' => $mainConfig->get( 'SQLMode' ),
+ 'trxMode' => $isReadRequest ? 'DEFERRED' : 'IMMEDIATE'
];
if ( in_array( $server['type'], $typesWithSchema, true ) ) {
$server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
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']['sqlMode'] = $mainConfig->get( 'SQLMode' );
}
+ $serversCheck = $lbConf['serverTemplate'] ?? [];
}
+ self::sanityCheckServerConfig( $serversCheck, $mainConfig );
$lbConf = self::applyDefaultCaching( $lbConf, $srvCace, $mainStash, $wanCache );
return $lbConf;
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
"\$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 );
"\$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 );