Convert ParserOutputAccess to PageRecord.

Still needs to downcast to WikiPage in 2 places:

1. To check get a ContentHandler and check if content model
is cacheable. We probably should just make all content models
cacheable.
2. To call WikiPage::triggerOpportunisticLinksUpdate. I have
an elaborate plan for this one, but it will be done separately.

Change-Id: Ifd9ab0155dc1fad0c1608dafea05d16292afd057
This commit is contained in:
Petr Pchelko 2021-04-02 20:12:43 -06:00
parent 3a047b749b
commit cd66d7c335
5 changed files with 66 additions and 28 deletions

View file

@ -1020,10 +1020,13 @@ return [
return new ParserOutputAccess( return new ParserOutputAccess(
$services->getParserCache(), $services->getParserCache(),
$services->getParserCacheFactory()->getRevisionOutputCache( 'rcache' ), $services->getParserCacheFactory()->getRevisionOutputCache( 'rcache' ),
$services->getRevisionLookup(),
$services->getRevisionRenderer(), $services->getRevisionRenderer(),
$services->getStatsdDataFactory(), $services->getStatsdDataFactory(),
$services->getDBLoadBalancerFactory(), $services->getDBLoadBalancerFactory(),
LoggerFactory::getProvider() LoggerFactory::getProvider(),
$services->getWikiPageFactory(),
$services->getTitleFormatter()
); );
}, },

View file

@ -25,6 +25,7 @@ use IBufferingStatsdDataFactory;
use InvalidArgumentException; use InvalidArgumentException;
use MediaWiki\Logger\Spi as LoggerSpi; use MediaWiki\Logger\Spi as LoggerSpi;
use MediaWiki\Parser\RevisionOutputCache; use MediaWiki\Parser\RevisionOutputCache;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionRenderer; use MediaWiki\Revision\RevisionRenderer;
use ParserCache; use ParserCache;
@ -34,8 +35,8 @@ use PoolWorkArticleView;
use PoolWorkArticleViewCurrent; use PoolWorkArticleViewCurrent;
use PoolWorkArticleViewOld; use PoolWorkArticleViewOld;
use Status; use Status;
use TitleFormatter;
use Wikimedia\Rdbms\ILBFactory; use Wikimedia\Rdbms\ILBFactory;
use WikiPage;
/** /**
* Service for getting rendered output of a given page. * Service for getting rendered output of a given page.
@ -92,6 +93,9 @@ class ParserOutputAccess {
*/ */
private $secondaryCache; private $secondaryCache;
/** @var RevisionLookup */
private $revisionLookup;
/** @var RevisionRenderer */ /** @var RevisionRenderer */
private $revisionRenderer; private $revisionRenderer;
@ -104,41 +108,56 @@ class ParserOutputAccess {
/** @var LoggerSpi */ /** @var LoggerSpi */
private $loggerSpi; private $loggerSpi;
/** @var WikiPageFactory */
private $wikiPageFactory;
/** @var TitleFormatter */
private $titleFormatter;
/** /**
* @param ParserCache $primaryCache * @param ParserCache $primaryCache
* @param RevisionOutputCache $secondaryCache * @param RevisionOutputCache $secondaryCache
* @param RevisionLookup $revisionLookup
* @param RevisionRenderer $revisionRenderer * @param RevisionRenderer $revisionRenderer
* @param IBufferingStatsdDataFactory $statsDataFactory * @param IBufferingStatsdDataFactory $statsDataFactory
* @param ILBFactory $lbFactory * @param ILBFactory $lbFactory
* @param LoggerSpi $loggerSpi * @param LoggerSpi $loggerSpi
* @param WikiPageFactory $wikiPageFactory
* @param TitleFormatter $titleFormatter
*/ */
public function __construct( public function __construct(
ParserCache $primaryCache, ParserCache $primaryCache,
RevisionOutputCache $secondaryCache, RevisionOutputCache $secondaryCache,
RevisionLookup $revisionLookup,
RevisionRenderer $revisionRenderer, RevisionRenderer $revisionRenderer,
IBufferingStatsdDataFactory $statsDataFactory, IBufferingStatsdDataFactory $statsDataFactory,
ILBFactory $lbFactory, ILBFactory $lbFactory,
LoggerSpi $loggerSpi LoggerSpi $loggerSpi,
WikiPageFactory $wikiPageFactory,
TitleFormatter $titleFormatter
) { ) {
$this->primaryCache = $primaryCache; $this->primaryCache = $primaryCache;
$this->secondaryCache = $secondaryCache; $this->secondaryCache = $secondaryCache;
$this->revisionLookup = $revisionLookup;
$this->revisionRenderer = $revisionRenderer; $this->revisionRenderer = $revisionRenderer;
$this->statsDataFactory = $statsDataFactory; $this->statsDataFactory = $statsDataFactory;
$this->lbFactory = $lbFactory; $this->lbFactory = $lbFactory;
$this->loggerSpi = $loggerSpi; $this->loggerSpi = $loggerSpi;
$this->wikiPageFactory = $wikiPageFactory;
$this->titleFormatter = $titleFormatter;
} }
/** /**
* Use a cache? * Use a cache?
* *
* @param WikiPage $page * @param PageRecord $page
* @param ParserOptions $parserOptions ParserOptions to check * @param ParserOptions $parserOptions ParserOptions to check
* @param RevisionRecord|null $rev * @param RevisionRecord|null $rev
* *
* @return string One of the CACHE_XXX constants. * @return string One of the CACHE_XXX constants.
*/ */
private function shouldUseCache( private function shouldUseCache(
WikiPage $page, PageRecord $page,
ParserOptions $parserOptions, ParserOptions $parserOptions,
?RevisionRecord $rev ?RevisionRecord $rev
) { ) {
@ -151,11 +170,12 @@ class ParserOutputAccess {
// NOTE: when we allow caching of old revisions in the future, // NOTE: when we allow caching of old revisions in the future,
// we must not allow caching of deleted revisions. // we must not allow caching of deleted revisions.
if ( !$page->exists() || !$page->getContentHandler()->isParserCacheSupported() ) { $wikiPage = $this->wikiPageFactory->newFromTitle( $page );
if ( !$page->exists() || !$wikiPage->getContentHandler()->isParserCacheSupported() ) {
return self::CACHE_NONE; return self::CACHE_NONE;
} }
if ( !$rev || $rev->getId() === $page->getLatest() ) { if ( !$rev || $rev->getId() === $page->getLatest( PageRecord::LOCAL ) ) {
// current revision // current revision
return self::CACHE_PRIMARY; return self::CACHE_PRIMARY;
} }
@ -171,7 +191,7 @@ class ParserOutputAccess {
/** /**
* Returns the rendered output for the given page if it is present in the cache. * Returns the rendered output for the given page if it is present in the cache.
* *
* @param WikiPage $page * @param PageRecord $page
* @param ParserOptions $parserOptions * @param ParserOptions $parserOptions
* @param RevisionRecord|null $revision * @param RevisionRecord|null $revision
* @param int $options Bitfield using the OPT_XXX constants * @param int $options Bitfield using the OPT_XXX constants
@ -179,7 +199,7 @@ class ParserOutputAccess {
* @return ParserOutput|null * @return ParserOutput|null
*/ */
public function getCachedParserOutput( public function getCachedParserOutput(
WikiPage $page, PageRecord $page,
ParserOptions $parserOptions, ParserOptions $parserOptions,
?RevisionRecord $revision = null, ?RevisionRecord $revision = null,
int $options = 0 int $options = 0
@ -204,7 +224,7 @@ class ParserOutputAccess {
* Returns the rendered output for the given page. * Returns the rendered output for the given page.
* Caching and concurrency control is applied. * Caching and concurrency control is applied.
* *
* @param WikiPage $page * @param PageRecord $page
* @param ParserOptions $parserOptions * @param ParserOptions $parserOptions
* @param RevisionRecord|null $revision * @param RevisionRecord|null $revision
* @param int $options Bitfield using the OPT_XXX constants * @param int $options Bitfield using the OPT_XXX constants
@ -223,7 +243,7 @@ class ParserOutputAccess {
* - 'nopagetext' (error) The page does not exist * - 'nopagetext' (error) The page does not exist
*/ */
public function getParserOutput( public function getParserOutput(
WikiPage $page, PageRecord $page,
ParserOptions $parserOptions, ParserOptions $parserOptions,
?RevisionRecord $revision = null, ?RevisionRecord $revision = null,
int $options = 0 int $options = 0
@ -245,7 +265,8 @@ class ParserOutputAccess {
} }
if ( !$revision ) { if ( !$revision ) {
$revision = $page->getRevisionRecord(); $revision = $page->getLatest() ?
$this->revisionLookup->getRevisionById( $page->getLatest() ) : null;
if ( !$revision ) { if ( !$revision ) {
$this->statsDataFactory->increment( "ParserOutputAccess.Status.norev" ); $this->statsDataFactory->increment( "ParserOutputAccess.Status.norev" );
@ -295,14 +316,14 @@ class ParserOutputAccess {
} }
/** /**
* @param WikiPage $page * @param PageRecord $page
* @param RevisionRecord|null $revision * @param RevisionRecord|null $revision
* @param int $options * @param int $options
* *
* @return Status|null * @return Status|null
*/ */
private function checkPreconditions( private function checkPreconditions(
WikiPage $page, PageRecord $page,
?RevisionRecord $revision = null, ?RevisionRecord $revision = null,
int $options = 0 int $options = 0
): ?Status { ): ?Status {
@ -330,7 +351,7 @@ class ParserOutputAccess {
'missing-revision-permission', 'missing-revision-permission',
$revision->getId(), $revision->getId(),
$revision->getTimestamp(), $revision->getTimestamp(),
$page->getTitle()->getPrefixedDBkey() $this->titleFormatter->getPrefixedDBkey( $page )
); );
} }
} }
@ -339,15 +360,15 @@ class ParserOutputAccess {
} }
/** /**
* @param WikiPage $page * @param PageRecord $page
* @param ParserOptions $parserOptions * @param ParserOptions $parserOptions
* @param RevisionRecord|null $revision * @param RevisionRecord $revision
* @param int $options * @param int $options
* *
* @return PoolWorkArticleView * @return PoolWorkArticleView
*/ */
private function newPoolWorkArticleView( private function newPoolWorkArticleView(
WikiPage $page, PageRecord $page,
ParserOptions $parserOptions, ParserOptions $parserOptions,
RevisionRecord $revision, RevisionRecord $revision,
int $options int $options
@ -376,7 +397,8 @@ class ParserOutputAccess {
$this->revisionRenderer, $this->revisionRenderer,
$this->primaryCache, $this->primaryCache,
$this->lbFactory, $this->lbFactory,
$this->loggerSpi $this->loggerSpi,
$this->wikiPageFactory
); );
case $useCache == self::CACHE_SECONDARY: case $useCache == self::CACHE_SECONDARY:

View file

@ -19,6 +19,8 @@
*/ */
use MediaWiki\Logger\Spi as LoggerSpi; use MediaWiki\Logger\Spi as LoggerSpi;
use MediaWiki\Page\PageRecord;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionRenderer; use MediaWiki\Revision\RevisionRenderer;
use Wikimedia\Rdbms\ILBFactory; use Wikimedia\Rdbms\ILBFactory;
@ -33,7 +35,7 @@ class PoolWorkArticleViewCurrent extends PoolWorkArticleView {
/** @var string */ /** @var string */
private $workKey; private $workKey;
/** @var WikiPage */ /** @var PageRecord */
private $page; private $page;
/** @var ParserCache */ /** @var ParserCache */
@ -42,29 +44,34 @@ class PoolWorkArticleViewCurrent extends PoolWorkArticleView {
/** @var ILBFactory */ /** @var ILBFactory */
private $lbFactory; private $lbFactory;
/** @var WikiPageFactory */
private $wikiPageFactory;
/** /**
* @param string $workKey * @param string $workKey
* @param WikiPage $page * @param PageRecord $page
* @param RevisionRecord $revision Revision to render * @param RevisionRecord $revision Revision to render
* @param ParserOptions $parserOptions ParserOptions to use for the parse * @param ParserOptions $parserOptions ParserOptions to use for the parse
* @param RevisionRenderer $revisionRenderer * @param RevisionRenderer $revisionRenderer
* @param ParserCache $parserCache * @param ParserCache $parserCache
* @param ILBFactory $lbFactory * @param ILBFactory $lbFactory
* @param LoggerSpi $loggerSpi * @param LoggerSpi $loggerSpi
* @param WikiPageFactory $wikiPageFactory
*/ */
public function __construct( public function __construct(
string $workKey, string $workKey,
WikiPage $page, PageRecord $page,
RevisionRecord $revision, RevisionRecord $revision,
ParserOptions $parserOptions, ParserOptions $parserOptions,
RevisionRenderer $revisionRenderer, RevisionRenderer $revisionRenderer,
ParserCache $parserCache, ParserCache $parserCache,
ILBFactory $lbFactory, ILBFactory $lbFactory,
LoggerSpi $loggerSpi LoggerSpi $loggerSpi,
WikiPageFactory $wikiPageFactory
) { ) {
// TODO: Remove support for partially initialized RevisionRecord instances once // TODO: Remove support for partially initialized RevisionRecord instances once
// Article no longer uses fake revisions. // Article no longer uses fake revisions.
if ( $revision->getPageId() && $revision->getPageId() !== $page->getTitle()->getArticleID() ) { if ( $revision->getPageId() && $revision->getPageId() !== $page->getId() ) {
throw new InvalidArgumentException( '$page parameter mismatches $revision parameter' ); throw new InvalidArgumentException( '$page parameter mismatches $revision parameter' );
} }
@ -74,6 +81,7 @@ class PoolWorkArticleViewCurrent extends PoolWorkArticleView {
$this->page = $page; $this->page = $page;
$this->parserCache = $parserCache; $this->parserCache = $parserCache;
$this->lbFactory = $lbFactory; $this->lbFactory = $lbFactory;
$this->wikiPageFactory = $wikiPageFactory;
$this->cacheable = true; $this->cacheable = true;
} }
@ -95,7 +103,8 @@ class PoolWorkArticleViewCurrent extends PoolWorkArticleView {
* @param ParserOutput $output * @param ParserOutput $output
*/ */
protected function afterWork( ParserOutput $output ) { protected function afterWork( ParserOutput $output ) {
$this->page->triggerOpportunisticLinksUpdate( $this->parserOutput ); $this->wikiPageFactory->newFromTitle( $this->page )
->triggerOpportunisticLinksUpdate( $this->parserOutput );
} }
/** /**

View file

@ -144,10 +144,13 @@ class ParserOutputAccessTest extends MediaWikiIntegrationTestCase {
return new ParserOutputAccess( return new ParserOutputAccess(
$parserCache, $parserCache,
$revisionOutputCache, $revisionOutputCache,
$this->getServiceContainer()->getRevisionLookup(),
$revRenderer, $revRenderer,
$stats, $stats,
$lbFactory, $lbFactory,
$this->getLoggerSpi() $this->getLoggerSpi(),
$this->getServiceContainer()->getWikiPageFactory(),
$this->getServiceContainer()->getTitleFormatter()
); );
} }
@ -251,7 +254,7 @@ class ParserOutputAccessTest extends MediaWikiIntegrationTestCase {
$revisionStore = $this->createNoOpMock( $revisionStore = $this->createNoOpMock(
RevisionStore::class, RevisionStore::class,
[ 'getRevisionByTitle', 'getKnownCurrentRevision' ] [ 'getRevisionByTitle', 'getKnownCurrentRevision', 'getRevisionById' ]
); );
$revisionStore->method( 'getRevisionById' )->willReturn( null ); $revisionStore->method( 'getRevisionById' )->willReturn( null );
$revisionStore->method( 'getRevisionByTitle' )->willReturn( null ); $revisionStore->method( 'getRevisionByTitle' )->willReturn( null );

View file

@ -45,7 +45,8 @@ class PoolWorkArticleViewCurrentTest extends PoolWorkArticleViewTest {
$revisionRenderer, $revisionRenderer,
$parserCache, $parserCache,
$lbFactory, $lbFactory,
$this->getLoggerSpi() $this->getLoggerSpi(),
$this->getServiceContainer()->getWikiPageFactory()
); );
} }