* Added CentralIdLookup, a service that allows extensions needing a concept of
"central" users to get that without having to know about specific central
authentication extensions.
+* $wgMaxUserDBWriteDuration added to limit huge user-generated transactions.
+ Regular web request transactions that takes longer than this are aborted.
=== External library changes in 1.27 ===
==== Upgraded external libraries ====
'DBQueryError' => __DIR__ . '/includes/db/DatabaseError.php',
'DBReadOnlyError' => __DIR__ . '/includes/db/DatabaseError.php',
'DBSiteStore' => __DIR__ . '/includes/site/DBSiteStore.php',
+ 'DBTransactionError' => __DIR__ . '/includes/db/DatabaseError.php',
'DBUnexpectedError' => __DIR__ . '/includes/db/DatabaseError.php',
'DataUpdate' => __DIR__ . '/includes/deferred/DataUpdate.php',
'Database' => __DIR__ . '/includes/db/Database.php',
*/
$wgPopularPasswordFile = __DIR__ . '/../serialized/commonpasswords.cdb';
+/*
+ * Max time (in seconds) a user-generated transaction can spend in writes.
+ * If exceeded, the transaction is rolled back with an error instead of being committed.
+ *
+ * @var int|bool Disabled if false
+ * @since 1.27
+ */
+$wgMaxUserDBWriteDuration = false;
+
/**
* For really cool vim folding this needs to be at the end:
* vim: foldmarker=@{,@} foldmethod=marker
// Either all DBs should commit or none
ignore_user_abort( true );
- // Commit all changes and record ChronologyProtector positions
+ $config = $context->getConfig();
+
$factory = wfGetLBFactory();
+ // Check if any transaction was too big
+ $limit = $config->get( 'MaxUserDBWriteDuration' );
+ $factory->forEachLB( function ( LoadBalancer $lb ) use ( $limit ) {
+ $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $limit ) {
+ $time = $db->pendingWriteQueryDuration();
+ if ( $limit > 0 && $time > $limit ) {
+ throw new DBTransactionError(
+ $db,
+ wfMessage( 'transaction-duration-limit-exceeded', $time, $limit )->plain()
+ );
+ }
+ } );
+ } );
+ // Commit all changes
$factory->commitMasterChanges();
+ // Record ChronologyProtector positions
$factory->shutdown();
wfDebug( __METHOD__ . ': all transactions committed' );
// Set a cookie to tell all CDN edge nodes to "stick" the user to the
// DC that handles this POST request (e.g. the "master" data center)
$request = $context->getRequest();
- $config = $context->getConfig();
if ( $request->wasPosted() && $factory->hasOrMadeRecentMasterChanges() ) {
$expires = time() + $config->get( 'DataCenterUpdateStickTTL' );
$request->response()->setCookie( 'UseDC', 'master', $expires, array( 'prefix' => '' ) );
return $this->msg( 'readonly', 'Database is locked' );
}
}
+
+/**
+ * @ingroup Database
+ */
+class DBTransactionError extends DBExpectedError {
+}
"databaseerror-query": "Query: $1",
"databaseerror-function": "Function: $1",
"databaseerror-error": "Error: $1",
+ "transaction-duration-limit-exceeded": "In order to avoid creating high replication lag, this transaction was aborted because the write duration ($1) exceeded the $2 second limit.\nIf you are changing many items at once, trying doing multiple smaller operations instead.",
"laggedslavemode": "<strong>Warning:</strong> Page may not contain recent updates.",
"readonly": "Database locked",
"enterlockreason": "Enter a reason for the lock, including an estimate of when the lock will be released",
"spam_blanking": "All revisions contained links to $1, blanking",
"spam_deleting": "All revisions contained links to $1, deleting",
"simpleantispam-label": "Anti-spam check.\nDo <strong>not</strong> fill this in!",
- "autochange-username": "MediaWiki automatic change",
"pageinfo-header": "-",
"pageinfo-title": "Information for \"$1\"",
"pageinfo-not-current": "Sorry, it's impossible to provide this information for old revisions.",
"databaseerror-query": "Identifies, in the list of technical details, the [[wikipedia:SQL|SQL]] statement that failed.\nParameters:\n* $1 - SQL statement (shown within a box)\n{{Identical|Query}}",
"databaseerror-function": "Identifies, in the list of technical details, the function that tried to execute the database query.\nParameters:\n* $1 - Name of function\n{{Identical|Function}}",
"databaseerror-error": "Identifies, in the list of technical details, the error message the database server returned.\nParameters:\n* $1 - Error message from the database server, probably in English\n{{Identical|Error}}",
+ "transaction-duration-limit-exceeded": "Plain text error shown when DB updates take too long. Parameters:\n* $1 - time spent in database updates\n* $2 - maximum time allowed in database updates",
"laggedslavemode": "Used as warning when getting the timestamp of the latest version, if in LaggedSlaveMode.",
"readonly": "Used as title of error message when database is locked.",
"enterlockreason": "For developers when locking the database",