Aaron Schulz has uploaded a new change for review.
https://gerrit.wikimedia.org/r/264579
Change subject: Add IDatabase::getScopedLockAndFlush() method
......................................................................
Add IDatabase::getScopedLockAndFlush() method
This method is less manual and avoids the usual pitfalls of
not unlocking for a return statement or not flushing out any
prior transaction.
Change-Id: Ib1681244767de860105a68210e181e2f024ee525
---
M includes/db/DBConnRef.php
M includes/db/Database.php
M includes/db/IDatabase.php
M includes/jobqueue/jobs/CategoryMembershipChangeJob.php
4 files changed, 43 insertions(+), 14 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/79/264579/1
diff --git a/includes/db/DBConnRef.php b/includes/db/DBConnRef.php
index f09de4f..264ee11 100644
--- a/includes/db/DBConnRef.php
+++ b/includes/db/DBConnRef.php
@@ -505,6 +505,10 @@
return $this->__call( __FUNCTION__, func_get_args() );
}
+ public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
public function namedLocksEnqueue() {
return $this->__call( __FUNCTION__, func_get_args() );
}
diff --git a/includes/db/Database.php b/includes/db/Database.php
index 1835958..dc1570e 100644
--- a/includes/db/Database.php
+++ b/includes/db/Database.php
@@ -3167,6 +3167,21 @@
return true;
}
+ public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+ if ( !$this->lock( $lockKey, $fname, $timeout ) ) {
+ return null;
+ }
+
+ $that = $this;
+ $unlocker = new ScopedCallback( function () use ( $that,
$lockKey, $fname ) {
+ $that->unlock( $lockKey, $fname );
+ } );
+
+ $this->commit( __METHOD__, 'flush' );
+
+ return $unlocker;
+ }
+
public function namedLocksEnqueue() {
return false;
}
diff --git a/includes/db/IDatabase.php b/includes/db/IDatabase.php
index c72218a..e708d93 100644
--- a/includes/db/IDatabase.php
+++ b/includes/db/IDatabase.php
@@ -1489,8 +1489,8 @@
* Named locks are not related to transactions
*
* @param string $lockName Name of lock to aquire
- * @param string $method Name of method calling us
- * @param int $timeout
+ * @param string $method Name of the calling method
+ * @param int $timeout Acquisition timeout in seconds
* @return bool
*/
public function lock( $lockName, $method, $timeout = 5 );
@@ -1501,7 +1501,7 @@
* Named locks are not related to transactions
*
* @param string $lockName Name of lock to release
- * @param string $method Name of method calling us
+ * @param string $method Name of the calling method
*
* @return int Returns 1 if the lock was released, 0 if the lock was
not established
* by this thread (in which case the lock is not released), and NULL if
the named
@@ -1510,6 +1510,25 @@
public function unlock( $lockName, $method );
/**
+ * Acquire a named lock, flush any transaction, and return an RAII
style unlocker object
+ *
+ * This is suitiable for transactions that need to be serialized using
cooperative locks,
+ * where each transaction can see each others' changes. Any transaction
is flushed to clear
+ * out stale REPEATABLE-READ snapshot data. Once the returned object
falls out of PHP scope,
+ * the lock will be released.
+ *
+ * If the lock acquisition failed, then no transaction flush happens,
and null is returned.
+ *
+ * @param string $lockKey Name of lock to release
+ * @param string $fname Name of the calling method
+ * @param int $timeout Acquisition timeout in seconds
+ * @return ScopedCallback|null
+ * @throws DBUnexpectedError
+ * @since 1.27
+ */
+ public function getScopedLockAndFlush( $lockKey, $fname, $timeout );
+
+ /**
* Check to see if a named lock used by lock() use blocking queues
*
* @return bool
diff --git a/includes/jobqueue/jobs/CategoryMembershipChangeJob.php
b/includes/jobqueue/jobs/CategoryMembershipChangeJob.php
index c9e20a9..3323850 100644
--- a/includes/jobqueue/jobs/CategoryMembershipChangeJob.php
+++ b/includes/jobqueue/jobs/CategoryMembershipChangeJob.php
@@ -51,19 +51,12 @@
$dbw = wfGetDB( DB_MASTER );
// Use a named lock so that jobs for this page see each others'
changes
- $fname = __METHOD__;
$lockKey = "CategoryMembershipUpdates:{$page->getId()}";
- if ( !$dbw->lock( $lockKey, $fname, 10 ) ) {
+ $scopedLock = $dbw->getScopedLockAndFlush( $lockKey,
__METHOD__, 10 );
+ if ( !$scopedLock ) {
$this->setLastError( "Could not acquire lock
'$lockKey'" );
return false;
}
-
- $unlocker = new ScopedCallback( function () use ( $dbw,
$lockKey, $fname ) {
- $dbw->unlock( $lockKey, $fname );
- } );
-
- // Sanity: clear any DB transaction snapshot
- $dbw->commit( __METHOD__, 'flush' );
$cutoffUnix = wfTimestamp( TS_UNIX,
$this->params['revTimestamp'] );
// Using ENQUEUE_FUDGE_SEC handles jobs inserted out of
revision order due to the delay
@@ -120,8 +113,6 @@
foreach ( $res as $row ) {
$this->notifyUpdatesForRevision( $page,
Revision::newFromRow( $row ) );
}
-
- ScopedCallback::consume( $unlocker );
return true;
}
--
To view, visit https://gerrit.wikimedia.org/r/264579
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib1681244767de860105a68210e181e2f024ee525
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits