MediaWiki  master
PoolWorkArticleViewCurrent.php
Go to the documentation of this file.
1 <?php
21 use MediaWiki\Logger\Spi as LoggerSpi;
30 
38  private $workKey;
40  private $page;
42  private $parserCache;
44  private $lbFactory;
46  private $wikiPageFactory;
48  private bool $triggerLinksUpdate;
49  private ChronologyProtector $chronologyProtector;
50 
65  public function __construct(
66  string $workKey,
67  PageRecord $page,
70  RevisionRenderer $revisionRenderer,
71  ParserCache $parserCache,
72  ILBFactory $lbFactory,
73  ChronologyProtector $chronologyProtector,
74  LoggerSpi $loggerSpi,
75  WikiPageFactory $wikiPageFactory,
76  bool $cacheable = true,
77  bool $triggerLinksUpdate = false
78  ) {
79  // TODO: Remove support for partially initialized RevisionRecord instances once
80  // Article no longer uses fake revisions.
81  if ( $revision->getPageId() && $revision->getPageId() !== $page->getId() ) {
82  throw new InvalidArgumentException( '$page parameter mismatches $revision parameter' );
83  }
84 
85  parent::__construct( $workKey, $revision, $parserOptions, $revisionRenderer, $loggerSpi );
86 
87  $this->workKey = $workKey;
88  $this->page = $page;
89  $this->parserCache = $parserCache;
90  $this->lbFactory = $lbFactory;
91  $this->chronologyProtector = $chronologyProtector;
92  $this->wikiPageFactory = $wikiPageFactory;
93  $this->cacheable = $cacheable;
94  $this->triggerLinksUpdate = $triggerLinksUpdate;
95  }
96 
100  public function doWork() {
101  // Reduce effects of race conditions for slow parses (T48014)
102  $cacheTime = wfTimestampNow();
103 
104  $status = $this->renderRevision();
106  $output = $status->getValue();
107 
108  if ( $output ) {
109  if ( $this->cacheable && $output->isCacheable() ) {
110  $this->parserCache->save(
111  $output,
112  $this->page,
113  $this->parserOptions,
114  $cacheTime,
115  $this->revision->getId()
116  );
117  }
118 
119  if ( $this->triggerLinksUpdate ) {
120  $this->wikiPageFactory->newFromTitle( $this->page )
121  ->triggerOpportunisticLinksUpdate( $output );
122  }
123  }
124 
125  return $status;
126  }
127 
131  public function getCachedWork() {
132  $parserOutput = $this->parserCache->get( $this->page, $this->parserOptions );
133 
134  $logger = $this->loggerSpi->getLogger( 'PoolWorkArticleView' );
135  $logger->debug( $parserOutput ? 'parser cache hit' : 'parser cache miss' );
136 
137  return $parserOutput ? Status::newGood( $parserOutput ) : false;
138  }
139 
144  public function fallback( $fast ) {
145  $parserOutput = $this->parserCache->getDirty( $this->page, $this->parserOptions );
146 
147  $logger = $this->loggerSpi->getLogger( 'dirty' );
148 
149  if ( !$parserOutput ) {
150  $logger->info( 'dirty missing' );
151  return false;
152  }
153 
154  if ( $fast ) {
155  /* Check if the stale response is from before the last write to the
156  * DB by this user. Declining to return a stale response in this
157  * case ensures that the user will see their own edit after page
158  * save.
159  *
160  * Note that the CP touch time is the timestamp of the shutdown of
161  * the save request, so there is a bias towards avoiding fast stale
162  * responses of potentially several seconds.
163  */
164  $lastWriteTime = $this->chronologyProtector->getTouched( $this->lbFactory->getMainLB() );
165  $cacheTime = MWTimestamp::convert( TS_UNIX, $parserOutput->getCacheTime() );
166  if ( $lastWriteTime && $cacheTime <= $lastWriteTime ) {
167  $logger->info(
168  'declining to send dirty output since cache time ' .
169  '{cacheTime} is before last write time {lastWriteTime}',
170  [
171  'workKey' => $this->workKey,
172  'cacheTime' => $cacheTime,
173  'lastWriteTime' => $lastWriteTime,
174  ]
175  );
176  // Forget this ParserOutput -- we will request it again if
177  // necessary in slow mode. There might be a newer entry
178  // available by that time.
179  return false;
180  }
181  }
182 
183  $logger->info( $fast ? 'fast dirty output' : 'dirty output', [ 'workKey' => $this->workKey ] );
184 
185  $status = Status::newGood( $parserOutput );
186  $status->warning( 'view-pool-dirty-output' );
187  $status->warning( $fast ? 'view-pool-contention' : 'view-pool-overload' );
188  return $status;
189  }
190 
191 }
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Service for creating WikiPage objects.
Page revision base class.
getPageId( $wikiId=self::LOCAL)
Get the page ID.
The RevisionRenderer service provides access to rendered output for revisions.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:58
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:48
Cache for ParserOutput objects corresponding to the latest page revisions.
Definition: ParserCache.php:64
Set options of the Parser.
PoolWorkArticleView for the current revision of a page, using ParserCache.
__construct(string $workKey, PageRecord $page, RevisionRecord $revision, ParserOptions $parserOptions, RevisionRenderer $revisionRenderer, ParserCache $parserCache, ILBFactory $lbFactory, ChronologyProtector $chronologyProtector, LoggerSpi $loggerSpi, WikiPageFactory $wikiPageFactory, bool $cacheable=true, bool $triggerLinksUpdate=false)
PoolCounter protected work wrapping RenderedRevision->getRevisionParserOutput.
ParserOptions $parserOptions
Provide a given client with protection against visible database lag.
Service provider interface for \Psr\Log\LoggerInterface implementation libraries.
Definition: Spi.php:38
Data record representing a page that is (or used to be, or could be) an editable page on a wiki.
Definition: PageRecord.php:26
getId( $wikiId=self::LOCAL)
Returns the page ID.
Manager of ILoadBalancer objects and, indirectly, IDatabase connections.
Definition: ILBFactory.php:46