Merge "Try harder to avoid parser cache pollution"
[lhc/web/wiklou.git] / includes / page / WikiPage.php
index 6d2cdeb..0e23a88 100644 (file)
@@ -23,6 +23,9 @@
 use \MediaWiki\Logger\LoggerFactory;
 use \MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\FakeResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DBError;
+use Wikimedia\Rdbms\DBUnexpectedError;
 
 /**
  * Class representing a MediaWiki article and history.
@@ -84,9 +87,10 @@ class WikiPage implements Page, IDBAccessObject {
         */
        protected $mLinksUpdated = '19700101000000';
 
-       const PURGE_CDN_CACHE = 1; // purge CDN cache for page variant URLs
-       const PURGE_CLUSTER_PCACHE = 2; // purge parser cache in the local datacenter
-       const PURGE_GLOBAL_PCACHE = 4; // set page_touched to clear parser cache in all datacenters
+       /** @deprecated since 1.29. Added in 1.28 for partial purging, no longer used. */
+       const PURGE_CDN_CACHE = 1;
+       const PURGE_CLUSTER_PCACHE = 2;
+       const PURGE_GLOBAL_PCACHE = 4;
        const PURGE_ALL = 7;
 
        /**
@@ -1051,6 +1055,13 @@ class WikiPage implements Page, IDBAccessObject {
        ) {
                $useParserCache =
                        ( !$forceParse ) && $this->shouldCheckParserCache( $parserOptions, $oldid );
+
+               if ( $useParserCache && !$parserOptions->isSafeToCache() ) {
+                       throw new InvalidArgumentException(
+                               'The supplied ParserOptions are not safe to cache. Fix the options or set $forceParse = true.'
+                       );
+               }
+
                wfDebug( __METHOD__ .
                        ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
                if ( $parserOptions->getStubThreshold() ) {
@@ -1096,10 +1107,11 @@ class WikiPage implements Page, IDBAccessObject {
 
        /**
         * Perform the actions of a page purging
-        * @param integer $flags Bitfield of WikiPage::PURGE_* constants
         * @return bool
+        * @note In 1.28 (and only 1.28), this took a $flags parameter that
+        *  controlled how much purging was done.
         */
-       public function doPurge( $flags = self::PURGE_ALL ) {
+       public function doPurge() {
                // Avoid PHP 7.1 warning of passing $this by reference
                $wikiPage = $this;
 
@@ -1107,30 +1119,15 @@ class WikiPage implements Page, IDBAccessObject {
                        return false;
                }
 
-               if ( ( $flags & self::PURGE_GLOBAL_PCACHE ) == self::PURGE_GLOBAL_PCACHE ) {
-                       // Set page_touched in the database to invalidate all DC caches
-                       $this->mTitle->invalidateCache();
-               } elseif ( ( $flags & self::PURGE_CLUSTER_PCACHE ) == self::PURGE_CLUSTER_PCACHE ) {
-                       // Delete the parser options key in the local cluster to invalidate the DC cache
-                       ParserCache::singleton()->deleteOptionsKey( $this );
-                       // Avoid sending HTTP 304s in ViewAction to the client who just issued the purge
-                       $cache = ObjectCache::getLocalClusterInstance();
-                       $cache->set(
-                               $cache->makeKey( 'page', 'last-dc-purge', $this->getId() ),
-                               wfTimestamp( TS_MW ),
-                               $cache::TTL_HOUR
-                       );
-               }
+               $this->mTitle->invalidateCache();
 
-               if ( ( $flags & self::PURGE_CDN_CACHE ) == self::PURGE_CDN_CACHE ) {
-                       // Clear any HTML file cache
-                       HTMLFileCache::clearFileCache( $this->getTitle() );
-                       // Send purge after any page_touched above update was committed
-                       DeferredUpdates::addUpdate(
-                               new CdnCacheUpdate( $this->mTitle->getCdnUrls() ),
-                               DeferredUpdates::PRESEND
-                       );
-               }
+               // Clear file cache
+               HTMLFileCache::clearFileCache( $this->getTitle() );
+               // Send purge after above page_touched update was committed
+               DeferredUpdates::addUpdate(
+                       new CdnCacheUpdate( $this->mTitle->getCdnUrls() ),
+                       DeferredUpdates::PRESEND
+               );
 
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
                        $messageCache = MessageCache::singleton();
@@ -1145,11 +1142,11 @@ class WikiPage implements Page, IDBAccessObject {
         *
         * @return string|bool TS_MW timestamp or false
         * @since 1.28
+        * @deprecated since 1.29. It will always return false.
         */
        public function getLastPurgeTimestamp() {
-               $cache = ObjectCache::getLocalClusterInstance();
-
-               return $cache->get( $cache->makeKey( 'page', 'last-dc-purge', $this->getId() ) );
+               wfDeprecated( __METHOD__, '1.29' );
+               return false;
        }
 
        /**
@@ -1187,7 +1184,7 @@ class WikiPage implements Page, IDBAccessObject {
                );
 
                if ( $dbw->affectedRows() > 0 ) {
-                       $newid = $pageId ?: $dbw->insertId();
+                       $newid = $pageId ? (int)$pageId : $dbw->insertId();
                        $this->mId = $newid;
                        $this->mTitle->resetArticleID( $newid );
 
@@ -2911,8 +2908,8 @@ class WikiPage implements Page, IDBAccessObject {
                $status->value = $logid;
 
                // Show log excerpt on 404 pages rather than just a link
-               $cache = ObjectCache::getMainStashInstance();
-               $key = wfMemcKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );
+               $cache = MediaWikiServices::getInstance()->getMainObjectStash();
+               $key = $cache->makeKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );
                $cache->set( $key, 1, $cache::TTL_DAY );
 
                return $status;
@@ -3262,6 +3259,9 @@ class WikiPage implements Page, IDBAccessObject {
 
                MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
 
+               // Invalidate caches of articles which include this page
+               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
+
                if ( $title->getNamespace() == NS_CATEGORY ) {
                        // Load the Category object, which will schedule a job to create
                        // the category table row if necessary. Checking a replica DB is ok
@@ -3503,7 +3503,10 @@ class WikiPage implements Page, IDBAccessObject {
                        );
                        foreach ( $rows as $row ) {
                                $cat = Category::newFromRow( $row );
-                               $cat->refreshCounts();
+                               // T166757: do the update after this DB commit
+                               DeferredUpdates::addCallableUpdate( function () use ( $cat ) {
+                                       $cat->refreshCounts();
+                               } );
                        }
                }
        }