'ContextSource' => 'includes/RequestContext.php',
'Cookie' => 'includes/Cookie.php',
'CookieJar' => 'includes/Cookie.php',
+ 'DeferrableUpdate' => 'includes/DeferredUpdates.php',
+ 'DeferredUpdates' => 'includes/DeferredUpdates.php',
'DiffHistoryBlob' => 'includes/HistoryBlob.php',
'DjVuImage' => 'includes/DjVuImage.php',
'DoubleReplacer' => 'includes/StringUtils.php',
--- /dev/null
+<?php
+/**
+ * Interface that deferrable updates should implement. Basically required so we
+ * can validate input on DeferredUpdates::addUpdate()
+ */
+interface DeferrableUpdate {
+ /**
+ * Perform the actual work
+ */
+ function doUpdate();
+}
+
+/**
+ * Class for mananging the deferred updates.
+ */
+class DeferredUpdates {
+ /**
+ * Store of updates to be deferred until the end of the request.
+ */
+ private static $updates = array();
+
+ /**
+ * Add an update to the deferred list
+ * @param $update DeferrableUpdate Some object that implements doUpdate()
+ */
+ public static function addUpdate( DeferrableUpdate $update ) {
+ array_push( self::$updates, $update );
+ }
+
+ /**
+ * HTMLCacheUpdates are the most common deferred update people use. This
+ * is a shortcut method for that.
+ * @see HTMLCacheUpdate::__construct()
+ */
+ public static function addHTMLCacheUpdate( $title, $table ) {
+ self::addUpdate( new HTMLCacheUpdate( $title, $table ) );
+ }
+
+ /**
+ * Do any deferred updates and clear the list
+ *
+ * @param $commit String: set to 'commit' to commit after every update to
+ * prevent lock contention
+ */
+ public static function doUpdates( $commit = '' ) {
+ global $wgDeferredUpdateList;
+
+ wfProfileIn( __METHOD__ );
+
+ $updates = array_merge( $wgDeferredUpdateList, self::$updates );
+
+ // No need to get master connections in case of empty updates array
+ if ( !count( $updates ) ) {
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+
+ $doCommit = $commit == 'commit';
+ if ( $doCommit ) {
+ $dbw = wfGetDB( DB_MASTER );
+ }
+
+ foreach ( $updates as $update ) {
+ $update->doUpdate();
+
+ if ( $doCommit && $dbw->trxLevel() ) {
+ $dbw->commit();
+ }
+ }
+
+ self::clearPendingUpdates();
+ wfProfileOut( __METHOD__ );
+ }
+
+ /**
+ * Clear all pending updates without performing them. Generally, you don't
+ * want or need to call this. Unit tests need it though.
+ */
+ public static function clearPendingUpdates() {
+ global $wgDeferredUpdateList;
+ $wgDeferredUpdateList = self::$updates = array();
+ }
+}
/**
* Do any deferred updates and clear the list
*
- * @param $commit String: set to 'commit' to commit after every update to
- * prevent lock contention
+ * @deprecated since 1.19
+ * @see DeferredUpdates::doUpdate()
*/
function wfDoUpdates( $commit = '' ) {
- global $wgDeferredUpdateList;
-
- wfProfileIn( __METHOD__ );
-
- // No need to get master connections in case of empty updates array
- if ( !count( $wgDeferredUpdateList ) ) {
- wfProfileOut( __METHOD__ );
- return;
- }
-
- $doCommit = $commit == 'commit';
- if ( $doCommit ) {
- $dbw = wfGetDB( DB_MASTER );
- }
-
- foreach ( $wgDeferredUpdateList as $update ) {
- $update->doUpdate();
-
- if ( $doCommit && $dbw->trxLevel() ) {
- $dbw->commit();
- }
- }
-
- $wgDeferredUpdateList = array();
- wfProfileOut( __METHOD__ );
+ DeferredUpdates::doUpdates( $commit );
}
/**
}
/**
- *
+ * Class for handling updates to the site_stats table
*/
-class SiteStatsUpdate {
+class SiteStatsUpdate implements DeferrableUpdate {
var $mViews, $mEdits, $mGood, $mPages, $mUsers;
* 'page_counter' field or use the 'hitcounter' table and then collect the data
* from that table to update the 'page_counter' field in a batch operation.
*/
-class ViewCountUpdate {
+class ViewCountUpdate implements DeferrableUpdate {
protected $id;
/**
// Output everything!
$this->context->getOutput()->output();
// Do any deferred jobs
- wfDoUpdates( 'commit' );
+ DeferredUpdates::doUpdates( 'commit' );
$this->doJobs();
wfProfileOut( __METHOD__ );
}
# Do updates right now unless deferral was requested
if ( !( $flags & EDIT_DEFER_UPDATES ) ) {
- wfDoUpdates();
+ DeferredUpdates::doUpdates();
}
// Return the new revision (or null) to the caller
public function doDeleteArticle(
$reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
) {
- global $wgDeferredUpdateList, $wgUseTrackbacks, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase, $wgUser;
+ global $wgUseTrackbacks, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase, $wgUser;
$user = is_null( $user ) ? $wgUser : $user;
wfDebug( __METHOD__ . "\n" );
return false;
}
- $u = new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 );
- array_push( $wgDeferredUpdateList, $u );
+ DeferredUpdates::addUpdate(
+ new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 )
+ );
// Bitfields to further suppress the content
if ( $suppress ) {
* @param $user User The relevant user
*/
public function doViewUpdates( User $user ) {
- global $wgDeferredUpdateList, $wgDisableCounters;
+ global $wgDisableCounters;
if ( wfReadOnly() ) {
return;
}
# Don't update page view counters on views from bot users (bug 14044)
if ( !$wgDisableCounters && !$user->isAllowed( 'bot' ) && $this->getId() ) {
- $wgDeferredUpdateList[] = new ViewCountUpdate( $this->getId() );
- $wgDeferredUpdateList[] = new SiteStatsUpdate( 1, 0, 0 );
+ DeferredUpdates::addUpdate( new ViewCountUpdate( $this->getId() ) );
+ DeferredUpdates::addUpdate( new SiteStatsUpdate( 1, 0, 0 ) );
}
# Update newtalk / watchlist notification status
* - null: don't change the article count
*/
public function doEditUpdates( Revision $revision, User $user, array $options = array() ) {
- global $wgDeferredUpdateList, $wgEnableParserCache;
+ global $wgEnableParserCache;
wfProfileIn( __METHOD__ );
$total = 0;
}
- $wgDeferredUpdateList[] = new SiteStatsUpdate( 0, 1, $good, $total );
- $wgDeferredUpdateList[] = new SearchUpdate( $id, $title, $text );
+ DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, $good, $total ) );
+ DeferredUpdates::addUpdate( new SearchUpdate( $id, $title, $text ) );
# If this is another user's talk page, update newtalk.
# Don't do this if $options['changed'] = false (null-edits) nor if
* @param $title Title object
*/
public static function onArticleCreate( $title ) {
- global $wgDeferredUpdateList;
-
# Update existence markers on article/talk tabs...
if ( $title->isTalkPage() ) {
$other = $title->getSubjectPage();
$title->deleteTitleProtection();
# Invalidate caches of distant articles which transclude this page
- $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
+ DeferredUpdates::addHTMLCacheUpdate( $title, 'globaltemplatelinks' );
}
/**
* @param $title Title
*/
public static function onArticleDelete( $title ) {
- global $wgDeferredUpdateList;
-
# Update existence markers on article/talk tabs...
if ( $title->isTalkPage() ) {
$other = $title->getSubjectPage();
RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $title );
# Invalidate caches of distant articles which transclude this page
- $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
+ DeferredUpdates::addHTMLCacheUpdate( $title, 'globaltemplatelinks' );
}
/**
* @todo: verify that $title is always a Title object (and never false or null), add Title hint to parameter $title
*/
public static function onArticleEdit( $title ) {
- global $wgDeferredUpdateList;
-
// Invalidate caches of articles which include this page
- $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'templatelinks' );
+ DeferredUpdates::addHTMLCacheUpdate( $title, 'templatelinks' );
// Invalidate caches of distant articles which transclude this page
- $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
+ DeferredUpdates::addHTMLCacheUpdate( $title, 'globaltemplatelinks' );
// Invalidate the caches of all pages which redirect here
- $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'redirect' );
+ DeferredUpdates::addHTMLCacheUpdate( $title, 'redirect' );
# Purge squid for this page only
$title->purgeSquid();
*
* @ingroup Cache
*/
-class HTMLCacheUpdate
-{
+class HTMLCacheUpdate implements DeferrableUpdate {
/**
* @var Title
*/
*
* @ingroup Search
*/
-class SearchUpdate {
+class SearchUpdate implements DeferrableUpdate {
private $mId = 0, $mNamespace, $mTitle, $mText;
private $mTitleWords;
}
wfWaitForSlaves();
// XXX: Don't let deferred jobs array get absurdly large (bug 24375)
- wfDoUpdates( 'commit' );
+ DeferredUpdates::doUpdates( 'commit' );
}
function progress( $string ) {
}
static function setUp() {
- global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
+ global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
$wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
$wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
$parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
$wgEnableParserCache = false;
- $wgDeferredUpdateList = array();
+ DeferredUpdates::clearPendingUpdates();
$wgMemc = wfGetMainCache();
$messageMemc = wfGetMessageCacheStorage();
$parserMemc = wfGetParserCacheStorage();
}
function setUp() {
- global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
+ global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
$wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
$wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
$parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
$wgEnableParserCache = false;
- $wgDeferredUpdateList = array();
+ DeferredUpdates::clearPendingUpdates();
$wgMemc = wfGetMainCache();
$messageMemc = wfGetMessageCacheStorage();
$parserMemc = wfGetParserCacheStorage();