aboutsummaryrefslogtreecommitdiffstats
path: root/includes
diff options
context:
space:
mode:
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>2025-04-07 11:38:35 +0000
committerGerrit Code Review <gerrit@wikimedia.org>2025-04-07 11:38:35 +0000
commit88aef6c1421f3543c67c8ee923386971d6e4ece6 (patch)
tree66678dead7bcf6f75d9939e7a5924724dfb6a217 /includes
parentb53bd618cc8a8fc18f5b1c04b56eb6c4941d1fd1 (diff)
parent2b65587e4d92e7f27661e8821b14f74ade939cfa (diff)
downloadmediawikicore-88aef6c1421f3543c67c8ee923386971d6e4ece6.tar.gz
mediawikicore-88aef6c1421f3543c67c8ee923386971d6e4ece6.zip
Merge "block: Fix DBS::acquireTarget() race using GET_LOCK()"
Diffstat (limited to 'includes')
-rw-r--r--includes/api/ApiMessageTrait.php1
-rw-r--r--includes/block/DatabaseBlockStore.php13
2 files changed, 14 insertions, 0 deletions
diff --git a/includes/api/ApiMessageTrait.php b/includes/api/ApiMessageTrait.php
index 8f796101ce2b..9c2bd7575117 100644
--- a/includes/api/ApiMessageTrait.php
+++ b/includes/api/ApiMessageTrait.php
@@ -67,6 +67,7 @@ trait ApiMessageTrait {
'importuploaderrorpartial' => 'partialupload',
'importuploaderrorsize' => 'filetoobig',
'importuploaderrortemp' => 'notempdir',
+ 'ipb-block-not-found' => 'alreadyblocked',
'ipb_already_blocked' => 'alreadyblocked',
'ipb_blocked_as_range' => 'blockedasrange',
'ipb_cant_unblock' => 'cantunblock',
diff --git a/includes/block/DatabaseBlockStore.php b/includes/block/DatabaseBlockStore.php
index c33157b58157..20f662e044d5 100644
--- a/includes/block/DatabaseBlockStore.php
+++ b/includes/block/DatabaseBlockStore.php
@@ -1044,6 +1044,7 @@ class DatabaseBlockStore {
$targetUserName = (string)$target;
$targetUserId = $target->getUserIdentity()->getId( $this->wikiId );
$targetConds = [ 'bt_user' => $targetUserId ];
+ $targetLockKey = $dbw->getDomainID() . ':block:u:' . $targetUserId;
} else {
$targetAddress = (string)$target;
$targetUserName = null;
@@ -1052,6 +1053,8 @@ class DatabaseBlockStore {
'bt_address' => $targetAddress,
'bt_auto' => $isAuto,
];
+ $targetLockKey = $dbw->getDomainID() . ':block:' .
+ ( $isAuto ? 'a' : 'i' ) . ':' . $targetAddress;
}
$condsWithCount = $targetConds;
@@ -1059,6 +1062,15 @@ class DatabaseBlockStore {
$condsWithCount['bt_count'] = $expectedTargetCount;
}
+ $dbw->lock( $targetLockKey, __METHOD__ );
+ $func = __METHOD__;
+ $dbw->onTransactionCommitOrIdle(
+ static function () use ( $dbw, $targetLockKey, $func ) {
+ $dbw->unlock( $targetLockKey, "$func.closure" );
+ },
+ __METHOD__
+ );
+
// This query locks the index gap when the target doesn't exist yet,
// so there is a risk of throttling adjacent block insertions,
// especially on small wikis which have larger gaps. If this proves to
@@ -1076,6 +1088,7 @@ class DatabaseBlockStore {
->select( [ 'bt_id', 'bt_count' ] )
->from( 'block_target' )
->where( $targetConds )
+ ->forUpdate()
->caller( __METHOD__ )
->fetchResultSet();
if ( $res->numRows() > 1 ) {