*
* @file
*/
+use MediaWiki\MediaWikiServices;
/**
* Job to add recent change entries mentioning category membership changes
return false; // deleted?
}
- $dbw = wfGetDB( DB_MASTER );
-
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $dbw = $lb->getConnection( 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' );
+ $dbr = wfGetDB( DB_REPLICA, [ 'recentchanges' ] );
+ // Wait till the replica DB is caught up so that jobs for this page see each others' changes
+ if ( !$lb->safeWaitForMasterPos( $dbr ) ) {
+ $this->setLastError( "Timed out while waiting for replica DB to catch up" );
+ return false;
+ }
+ // Clear any stale REPEATABLE-READ snapshot
+ $dbr->flushSnapshot( __METHOD__ );
$cutoffUnix = wfTimestamp( TS_UNIX, $this->params['revTimestamp'] );
// Using ENQUEUE_FUDGE_SEC handles jobs inserted out of revision order due to the delay
$cutoffUnix -= self::ENQUEUE_FUDGE_SEC;
// Get the newest revision that has a SRC_CATEGORIZE row...
- $row = $dbw->selectRow(
- array( 'revision', 'recentchanges' ),
- array( 'rev_timestamp', 'rev_id' ),
- array(
+ $row = $dbr->selectRow(
+ [ 'revision', 'recentchanges' ],
+ [ 'rev_timestamp', 'rev_id' ],
+ [
'rev_page' => $page->getId(),
- 'rev_timestamp >= ' . $dbw->addQuotes( $dbw->timestamp( $cutoffUnix ) )
- ),
+ 'rev_timestamp >= ' . $dbr->addQuotes( $dbr->timestamp( $cutoffUnix ) )
+ ],
__METHOD__,
- array( 'ORDER BY' => 'rev_timestamp DESC, rev_id DESC' ),
- array(
- 'recentchanges' => array(
+ [ 'ORDER BY' => 'rev_timestamp DESC, rev_id DESC' ],
+ [
+ 'recentchanges' => [
'INNER JOIN',
- array(
+ [
'rc_this_oldid = rev_id',
'rc_source' => RecentChange::SRC_CATEGORIZE,
// Allow rc_cur_id or rc_timestamp index usage
'rc_cur_id = rev_page',
'rc_timestamp >= rev_timestamp'
- )
- )
- )
+ ]
+ ]
+ ]
);
// Only consider revisions newer than any such revision
if ( $row ) {
// Find revisions to this page made around and after this revision which lack category
// notifications in recent changes. This lets jobs pick up were the last one left off.
- $encCutoff = $dbw->addQuotes( $dbw->timestamp( $cutoffUnix ) );
- $res = $dbw->select(
+ $encCutoff = $dbr->addQuotes( $dbr->timestamp( $cutoffUnix ) );
+ $res = $dbr->select(
'revision',
Revision::selectFields(),
- array(
+ [
'rev_page' => $page->getId(),
"rev_timestamp > $encCutoff" .
" OR (rev_timestamp = $encCutoff AND rev_id > $lastRevId)"
- ),
+ ],
__METHOD__,
- array( 'ORDER BY' => 'rev_timestamp ASC, rev_id ASC' )
+ [ 'ORDER BY' => 'rev_timestamp ASC, rev_id ASC' ]
);
// Apply all category updates in revision timestamp order
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
foreach ( $res as $row ) {
- $this->notifyUpdatesForRevision( $page, Revision::newFromRow( $row ) );
+ $this->notifyUpdatesForRevision( $lbFactory, $page, Revision::newFromRow( $row ) );
}
- ScopedCallback::consume( $unlocker );
-
return true;
}
/**
+ * @param LBFactory $lbFactory
* @param WikiPage $page
* @param Revision $newRev
* @throws MWException
*/
- protected function notifyUpdatesForRevision( WikiPage $page, Revision $newRev ) {
+ protected function notifyUpdatesForRevision(
+ LBFactory $lbFactory, WikiPage $page, Revision $newRev
+ ) {
$config = RequestContext::getMain()->getConfig();
$title = $page->getTitle();
return; // nothing to do
}
- $dbw = wfGetDB( DB_MASTER );
+ $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
+
$catMembChange = new CategoryMembershipChange( $title, $newRev );
$catMembChange->checkTemplateLinks();
$categoryTitle = Title::makeTitle( NS_CATEGORY, $categoryName );
$catMembChange->triggerCategoryAddedNotification( $categoryTitle );
if ( $insertCount++ && ( $insertCount % $batchSize ) == 0 ) {
- $dbw->commit( __METHOD__, 'flush' );
- wfGetLBFactory()->waitForReplication();
+ $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
}
}
$categoryTitle = Title::makeTitle( NS_CATEGORY, $categoryName );
$catMembChange->triggerCategoryRemovedNotification( $categoryTitle );
if ( $insertCount++ && ( $insertCount++ % $batchSize ) == 0 ) {
- $dbw->commit( __METHOD__, 'flush' );
- wfGetLBFactory()->waitForReplication();
+ $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
}
}
}
// up to date, neither of which are true.
$oldCategories = $oldRev
? $this->getCategoriesAtRev( $title, $oldRev, $parseTimestamp )
- : array();
+ : [];
// Parse the new revision and get the categories
$newCategories = $this->getCategoriesAtRev( $title, $newRev, $parseTimestamp );
$categoryInserts = array_values( array_diff( $newCategories, $oldCategories ) );
$categoryDeletes = array_values( array_diff( $oldCategories, $newCategories ) );
- return array( $categoryInserts, $categoryDeletes );
+ return [ $categoryInserts, $categoryDeletes ];
}
/**