Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
89.56% |
163 / 182 |
|
77.78% |
7 / 9 |
CRAP | |
0.00% |
0 / 1 |
ParserOutputAccess | |
89.56% |
163 / 182 |
|
77.78% |
7 / 9 |
69.81 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
shouldUseCache | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
8 | |||
getCachedParserOutput | |
68.97% |
20 / 29 |
|
0.00% |
0 / 1 |
23.65 | |||
getParserOutput | |
100.00% |
34 / 34 |
|
100.00% |
1 / 1 |
15 | |||
renderRevision | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
6 | |||
checkPreconditions | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
10 | |||
newPoolWorkArticleView | |
77.78% |
35 / 45 |
|
0.00% |
0 / 1 |
5.27 | |||
getPrimaryCache | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
getSecondaryCache | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | namespace MediaWiki\Page; |
21 | |
22 | use IBufferingStatsdDataFactory; |
23 | use InvalidArgumentException; |
24 | use MapCacheLRU; |
25 | use MediaWiki\Logger\Spi as LoggerSpi; |
26 | use MediaWiki\Parser\ParserCacheFactory; |
27 | use MediaWiki\Parser\ParserOutput; |
28 | use MediaWiki\Parser\Parsoid\PageBundleParserOutputConverter; |
29 | use MediaWiki\Parser\RevisionOutputCache; |
30 | use MediaWiki\PoolCounter\PoolCounterWork; |
31 | use MediaWiki\PoolCounter\PoolWorkArticleView; |
32 | use MediaWiki\PoolCounter\PoolWorkArticleViewCurrent; |
33 | use MediaWiki\PoolCounter\PoolWorkArticleViewOld; |
34 | use MediaWiki\Revision\RevisionLookup; |
35 | use MediaWiki\Revision\RevisionRecord; |
36 | use MediaWiki\Revision\RevisionRenderer; |
37 | use MediaWiki\Status\Status; |
38 | use MediaWiki\Title\TitleFormatter; |
39 | use ParserCache; |
40 | use ParserOptions; |
41 | use Wikimedia\Assert\Assert; |
42 | use Wikimedia\Parsoid\Parsoid; |
43 | use Wikimedia\Rdbms\ChronologyProtector; |
44 | use Wikimedia\Rdbms\ILBFactory; |
45 | |
46 | /** |
47 | * Service for getting rendered output of a given page. |
48 | * |
49 | * This is a high level service, encapsulating concerns like caching |
50 | * and stampede protection via PoolCounter. |
51 | * |
52 | * @since 1.36 |
53 | * @ingroup Page |
54 | */ |
55 | class ParserOutputAccess { |
56 | |
57 | /** @internal */ |
58 | public const PARSOID_PCACHE_NAME = 'parsoid-' . ParserCacheFactory::DEFAULT_NAME; |
59 | |
60 | /** @internal */ |
61 | public const PARSOID_RCACHE_NAME = 'parsoid-' . ParserCacheFactory::DEFAULT_RCACHE_NAME; |
62 | |
63 | /** |
64 | * @var int Do not check the cache before parsing (force parse) |
65 | */ |
66 | public const OPT_NO_CHECK_CACHE = 1; |
67 | |
68 | /** @var int Alias for NO_CHECK_CACHE */ |
69 | public const OPT_FORCE_PARSE = self::OPT_NO_CHECK_CACHE; |
70 | |
71 | /** |
72 | * @var int Do not update the cache after parsing. |
73 | */ |
74 | public const OPT_NO_UPDATE_CACHE = 2; |
75 | |
76 | /** |
77 | * @var int Bypass audience check for deleted/suppressed revisions. |
78 | * The caller is responsible for ensuring that unauthorized access is prevented. |
79 | * If not set, output generation will fail if the revision is not public. |
80 | */ |
81 | public const OPT_NO_AUDIENCE_CHECK = 4; |
82 | |
83 | /** |
84 | * @var int Do not check the cache before parsing, |
85 | * and do not update the cache after parsing (not cacheable). |
86 | */ |
87 | public const OPT_NO_CACHE = self::OPT_NO_UPDATE_CACHE | self::OPT_NO_CHECK_CACHE; |
88 | |
89 | /** |
90 | * @var int Do perform an opportunistic LinksUpdate on cache miss |
91 | * @since 1.41 |
92 | */ |
93 | public const OPT_LINKS_UPDATE = 8; |
94 | |
95 | /** |
96 | * Apply page view semantics. This relaxes some guarantees, specifically: |
97 | * - Use PoolCounter for stampede protection, causing the request to |
98 | * block until another process has finished rendering the content. |
99 | * - Allow stale parser output to be returned to prevent long waits for |
100 | * slow renders. |
101 | * - Allow cacheable placeholder output to be returned when PoolCounter |
102 | * fails to obtain a lock. See the PoolCounterConf setting for details. |
103 | * |
104 | * @see Bug T352837 |
105 | * @since 1.42 |
106 | */ |
107 | public const OPT_FOR_ARTICLE_VIEW = 16; |
108 | |
109 | /** |
110 | * @var int Ignore the profile version of the result from the cache. |
111 | * Otherwise, if it's not Parsoid's default, it will be invalidated. |
112 | */ |
113 | public const OPT_IGNORE_PROFILE_VERSION = 128; |
114 | |
115 | /** @var string Do not read or write any cache */ |
116 | private const CACHE_NONE = 'none'; |
117 | |
118 | /** @var string Use primary cache */ |
119 | private const CACHE_PRIMARY = 'primary'; |
120 | |
121 | /** @var string Use secondary cache */ |
122 | private const CACHE_SECONDARY = 'secondary'; |
123 | |
124 | private ParserCacheFactory $parserCacheFactory; |
125 | |
126 | /** |
127 | * In cases that an extension tries to get the same ParserOutput of |
128 | * the page right after it was parsed (T301310). |
129 | * @var MapCacheLRU<string,ParserOutput> |
130 | */ |
131 | private MapCacheLRU $localCache; |
132 | |
133 | /** @var RevisionLookup */ |
134 | private $revisionLookup; |
135 | |
136 | /** @var RevisionRenderer */ |
137 | private $revisionRenderer; |
138 | |
139 | /** @var IBufferingStatsdDataFactory */ |
140 | private $statsDataFactory; |
141 | |
142 | /** @var ILBFactory */ |
143 | private $lbFactory; |
144 | private ChronologyProtector $chronologyProtector; |
145 | |
146 | /** @var LoggerSpi */ |
147 | private $loggerSpi; |
148 | |
149 | /** @var WikiPageFactory */ |
150 | private $wikiPageFactory; |
151 | |
152 | /** @var TitleFormatter */ |
153 | private $titleFormatter; |
154 | |
155 | /** |
156 | * @param ParserCacheFactory $parserCacheFactory |
157 | * @param RevisionLookup $revisionLookup |
158 | * @param RevisionRenderer $revisionRenderer |
159 | * @param IBufferingStatsdDataFactory $statsDataFactory |
160 | * @param ILBFactory $lbFactory |
161 | * @param ChronologyProtector $chronologyProtector |
162 | * @param LoggerSpi $loggerSpi |
163 | * @param WikiPageFactory $wikiPageFactory |
164 | * @param TitleFormatter $titleFormatter |
165 | */ |
166 | public function __construct( |
167 | ParserCacheFactory $parserCacheFactory, |
168 | RevisionLookup $revisionLookup, |
169 | RevisionRenderer $revisionRenderer, |
170 | IBufferingStatsdDataFactory $statsDataFactory, |
171 | ILBFactory $lbFactory, |
172 | ChronologyProtector $chronologyProtector, |
173 | LoggerSpi $loggerSpi, |
174 | WikiPageFactory $wikiPageFactory, |
175 | TitleFormatter $titleFormatter |
176 | ) { |
177 | $this->parserCacheFactory = $parserCacheFactory; |
178 | $this->revisionLookup = $revisionLookup; |
179 | $this->revisionRenderer = $revisionRenderer; |
180 | $this->statsDataFactory = $statsDataFactory; |
181 | $this->lbFactory = $lbFactory; |
182 | $this->chronologyProtector = $chronologyProtector; |
183 | $this->loggerSpi = $loggerSpi; |
184 | $this->wikiPageFactory = $wikiPageFactory; |
185 | $this->titleFormatter = $titleFormatter; |
186 | |
187 | $this->localCache = new MapCacheLRU( 10 ); |
188 | } |
189 | |
190 | /** |
191 | * Use a cache? |
192 | * |
193 | * @param PageRecord $page |
194 | * @param RevisionRecord|null $rev |
195 | * |
196 | * @return string One of the CACHE_XXX constants. |
197 | */ |
198 | private function shouldUseCache( |
199 | PageRecord $page, |
200 | ?RevisionRecord $rev |
201 | ) { |
202 | if ( $rev && !$rev->getId() ) { |
203 | // The revision isn't from the database, so the output can't safely be cached. |
204 | return self::CACHE_NONE; |
205 | } |
206 | |
207 | // NOTE: Keep in sync with ParserWikiPage::shouldCheckParserCache(). |
208 | // NOTE: when we allow caching of old revisions in the future, |
209 | // we must not allow caching of deleted revisions. |
210 | |
211 | $wikiPage = $this->wikiPageFactory->newFromTitle( $page ); |
212 | if ( !$page->exists() || !$wikiPage->getContentHandler()->isParserCacheSupported() ) { |
213 | return self::CACHE_NONE; |
214 | } |
215 | |
216 | $isOld = $rev && $rev->getId() !== $page->getLatest(); |
217 | if ( !$isOld ) { |
218 | return self::CACHE_PRIMARY; |
219 | } |
220 | |
221 | if ( !$rev->audienceCan( RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_PUBLIC ) ) { |
222 | // deleted/suppressed revision |
223 | return self::CACHE_NONE; |
224 | } |
225 | |
226 | return self::CACHE_SECONDARY; |
227 | } |
228 | |
229 | /** |
230 | * Returns the rendered output for the given page if it is present in the cache. |
231 | * |
232 | * @param PageRecord $page |
233 | * @param ParserOptions $parserOptions |
234 | * @param RevisionRecord|null $revision |
235 | * @param int $options Bitfield using the OPT_XXX constants |
236 | * |
237 | * @return ParserOutput|null |
238 | */ |
239 | public function getCachedParserOutput( |
240 | PageRecord $page, |
241 | ParserOptions $parserOptions, |
242 | ?RevisionRecord $revision = null, |
243 | int $options = 0 |
244 | ): ?ParserOutput { |
245 | $isOld = $revision && $revision->getId() !== $page->getLatest(); |
246 | $useCache = $this->shouldUseCache( $page, $revision ); |
247 | $primaryCache = $this->getPrimaryCache( $parserOptions ); |
248 | $classCacheKey = $primaryCache->makeParserOutputKey( $page, $parserOptions ); |
249 | |
250 | if ( $useCache === self::CACHE_PRIMARY ) { |
251 | if ( $this->localCache->hasField( $classCacheKey, $page->getLatest() ) && !$isOld ) { |
252 | return $this->localCache->getField( $classCacheKey, $page->getLatest() ); |
253 | } |
254 | $output = $primaryCache->get( $page, $parserOptions ); |
255 | } elseif ( $useCache === self::CACHE_SECONDARY && $revision ) { |
256 | $secondaryCache = $this->getSecondaryCache( $parserOptions ); |
257 | $output = $secondaryCache->get( $revision, $parserOptions ); |
258 | } else { |
259 | $output = null; |
260 | } |
261 | |
262 | $notHitReason = 'miss'; |
263 | if ( |
264 | $output && !( $options & self::OPT_IGNORE_PROFILE_VERSION ) && |
265 | $parserOptions->getUseParsoid() |
266 | ) { |
267 | $pageBundleData = $output->getExtensionData( |
268 | PageBundleParserOutputConverter::PARSOID_PAGE_BUNDLE_KEY |
269 | ); |
270 | // T333606: Force a reparse if the version coming from cache is not the default |
271 | $cachedVersion = $pageBundleData['version'] ?? null; |
272 | if ( |
273 | $cachedVersion !== null && // T325137: BadContentModel, no sense in reparsing |
274 | $cachedVersion !== Parsoid::defaultHTMLVersion() |
275 | ) { |
276 | $notHitReason = 'obsolete'; |
277 | $output = null; |
278 | } |
279 | } |
280 | |
281 | if ( $output && !$isOld ) { |
282 | $this->localCache->setField( $classCacheKey, $page->getLatest(), $output ); |
283 | } |
284 | |
285 | if ( $output ) { |
286 | $this->statsDataFactory->increment( "ParserOutputAccess.Cache.$useCache.hit" ); |
287 | } else { |
288 | $this->statsDataFactory->increment( "ParserOutputAccess.Cache.$useCache.$notHitReason" ); |
289 | } |
290 | |
291 | return $output ?: null; // convert false to null |
292 | } |
293 | |
294 | /** |
295 | * Returns the rendered output for the given page. |
296 | * Caching and concurrency control is applied. |
297 | * |
298 | * @param PageRecord $page |
299 | * @param ParserOptions $parserOptions |
300 | * @param RevisionRecord|null $revision |
301 | * @param int $options Bitfield using the OPT_XXX constants |
302 | * |
303 | * @return Status containing a ParserOutput if no error occurred. |
304 | * Well known errors and warnings include the following messages: |
305 | * - 'view-pool-dirty-output' (warning) The output is dirty (from a stale cache entry). |
306 | * - 'view-pool-contention' (warning) Dirty output was returned immediately instead of |
307 | * waiting to acquire a work lock (when "fast stale" mode is enabled in PoolCounter). |
308 | * - 'view-pool-timeout' (warning) Dirty output was returned after failing to acquire |
309 | * a work lock (got QUEUE_FULL or TIMEOUT from PoolCounter). |
310 | * - 'pool-queuefull' (error) unable to acquire work lock, and no cached content found. |
311 | * - 'pool-timeout' (error) unable to acquire work lock, and no cached content found. |
312 | * - 'pool-servererror' (error) PoolCounterWork failed due to a lock service error. |
313 | * - 'pool-unknownerror' (error) PoolCounterWork failed for an unknown reason. |
314 | * - 'nopagetext' (error) The page does not exist |
315 | */ |
316 | public function getParserOutput( |
317 | PageRecord $page, |
318 | ParserOptions $parserOptions, |
319 | ?RevisionRecord $revision = null, |
320 | int $options = 0 |
321 | ): Status { |
322 | $error = $this->checkPreconditions( $page, $revision, $options ); |
323 | if ( $error ) { |
324 | $this->statsDataFactory->increment( "ParserOutputAccess.Case.error" ); |
325 | return $error; |
326 | } |
327 | |
328 | $isOld = $revision && $revision->getId() !== $page->getLatest(); |
329 | if ( $isOld ) { |
330 | $this->statsDataFactory->increment( 'ParserOutputAccess.Case.old' ); |
331 | } else { |
332 | $this->statsDataFactory->increment( 'ParserOutputAccess.Case.current' ); |
333 | } |
334 | |
335 | if ( !( $options & self::OPT_NO_CHECK_CACHE ) ) { |
336 | $output = $this->getCachedParserOutput( $page, $parserOptions, $revision ); |
337 | if ( $output ) { |
338 | return Status::newGood( $output ); |
339 | } |
340 | } |
341 | |
342 | if ( !$revision ) { |
343 | $revId = $page->getLatest(); |
344 | $revision = $revId ? $this->revisionLookup->getRevisionById( $revId ) : null; |
345 | |
346 | if ( !$revision ) { |
347 | $this->statsDataFactory->increment( "ParserOutputAccess.Status.norev" ); |
348 | return Status::newFatal( 'missing-revision', $revId ); |
349 | } |
350 | } |
351 | |
352 | if ( $options & self::OPT_FOR_ARTICLE_VIEW ) { |
353 | $work = $this->newPoolWorkArticleView( $page, $parserOptions, $revision, $options ); |
354 | /** @var Status $status */ |
355 | $status = $work->execute(); |
356 | } else { |
357 | $status = $this->renderRevision( $page, $parserOptions, $revision, $options ); |
358 | } |
359 | |
360 | $output = $status->getValue(); |
361 | Assert::postcondition( $output || !$status->isOK(), 'Inconsistent status' ); |
362 | |
363 | if ( $output && !$isOld ) { |
364 | $primaryCache = $this->getPrimaryCache( $parserOptions ); |
365 | $classCacheKey = $primaryCache->makeParserOutputKey( $page, $parserOptions ); |
366 | $this->localCache->setField( $classCacheKey, $page->getLatest(), $output ); |
367 | } |
368 | |
369 | if ( $status->isGood() ) { |
370 | $this->statsDataFactory->increment( 'ParserOutputAccess.Status.good' ); |
371 | } elseif ( $status->isOK() ) { |
372 | $this->statsDataFactory->increment( 'ParserOutputAccess.Status.ok' ); |
373 | } else { |
374 | $this->statsDataFactory->increment( 'ParserOutputAccess.Status.error' ); |
375 | } |
376 | |
377 | return $status; |
378 | } |
379 | |
380 | /** |
381 | * Render the given revision. |
382 | * |
383 | * This method will update the parser cache if appropriate, and will |
384 | * trigger a links update if OPT_LINKS_UPDATE is set. |
385 | * |
386 | * This method does not perform access checks, and will not load content |
387 | * from caches. The caller is assumed to have taken care of that. |
388 | * |
389 | * @see PoolWorkArticleView::renderRevision |
390 | */ |
391 | private function renderRevision( |
392 | PageRecord $page, |
393 | ParserOptions $parserOptions, |
394 | RevisionRecord $revision, |
395 | int $options |
396 | ): Status { |
397 | $this->statsDataFactory->increment( 'ParserOutputAccess.PoolWork.None' ); |
398 | |
399 | $renderedRev = $this->revisionRenderer->getRenderedRevision( |
400 | $revision, |
401 | $parserOptions, |
402 | null, |
403 | [ 'audience' => RevisionRecord::RAW ] |
404 | ); |
405 | |
406 | $output = $renderedRev->getRevisionParserOutput(); |
407 | |
408 | if ( !( $options & self::OPT_NO_UPDATE_CACHE ) && $output->isCacheable() ) { |
409 | $useCache = $this->shouldUseCache( $page, $revision ); |
410 | |
411 | if ( $useCache === self::CACHE_PRIMARY ) { |
412 | $primaryCache = $this->getPrimaryCache( $parserOptions ); |
413 | $primaryCache->save( $output, $page, $parserOptions ); |
414 | } elseif ( $useCache === self::CACHE_SECONDARY ) { |
415 | $secondaryCache = $this->getSecondaryCache( $parserOptions ); |
416 | $secondaryCache->save( $output, $revision, $parserOptions ); |
417 | } |
418 | } |
419 | |
420 | if ( $options & self::OPT_LINKS_UPDATE ) { |
421 | $this->wikiPageFactory->newFromTitle( $page ) |
422 | ->triggerOpportunisticLinksUpdate( $output ); |
423 | } |
424 | |
425 | return Status::newGood( $output ); |
426 | } |
427 | |
428 | /** |
429 | * @param PageRecord $page |
430 | * @param RevisionRecord|null $revision |
431 | * @param int $options |
432 | * |
433 | * @return Status|null |
434 | */ |
435 | private function checkPreconditions( |
436 | PageRecord $page, |
437 | ?RevisionRecord $revision = null, |
438 | int $options = 0 |
439 | ): ?Status { |
440 | if ( !$page->exists() ) { |
441 | return Status::newFatal( 'nopagetext' ); |
442 | } |
443 | |
444 | if ( !( $options & self::OPT_NO_UPDATE_CACHE ) && $revision && !$revision->getId() ) { |
445 | throw new InvalidArgumentException( |
446 | 'The revision does not have a known ID. Use OPT_NO_CACHE.' |
447 | ); |
448 | } |
449 | |
450 | if ( $revision && $revision->getPageId() !== $page->getId() ) { |
451 | throw new InvalidArgumentException( |
452 | 'The revision does not belong to the given page.' |
453 | ); |
454 | } |
455 | |
456 | if ( $revision && !( $options & self::OPT_NO_AUDIENCE_CHECK ) ) { |
457 | // NOTE: If per-user checks are desired, the caller should perform them and |
458 | // then set OPT_NO_AUDIENCE_CHECK if they passed. |
459 | if ( !$revision->audienceCan( RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_PUBLIC ) ) { |
460 | return Status::newFatal( |
461 | 'missing-revision-permission', |
462 | $revision->getId(), |
463 | $revision->getTimestamp(), |
464 | $this->titleFormatter->getPrefixedDBkey( $page ) |
465 | ); |
466 | } |
467 | } |
468 | |
469 | return null; |
470 | } |
471 | |
472 | /** |
473 | * @param PageRecord $page |
474 | * @param ParserOptions $parserOptions |
475 | * @param RevisionRecord $revision |
476 | * @param int $options |
477 | * |
478 | * @return PoolCounterWork |
479 | */ |
480 | protected function newPoolWorkArticleView( |
481 | PageRecord $page, |
482 | ParserOptions $parserOptions, |
483 | RevisionRecord $revision, |
484 | int $options |
485 | ): PoolCounterWork { |
486 | $useCache = $this->shouldUseCache( $page, $revision ); |
487 | |
488 | switch ( $useCache ) { |
489 | case self::CACHE_PRIMARY: |
490 | $this->statsDataFactory->increment( 'ParserOutputAccess.PoolWork.Current' ); |
491 | $primaryCache = $this->getPrimaryCache( $parserOptions ); |
492 | $parserCacheMetadata = $primaryCache->getMetadata( $page ); |
493 | $cacheKey = $primaryCache->makeParserOutputKey( $page, $parserOptions, |
494 | $parserCacheMetadata ? $parserCacheMetadata->getUsedOptions() : null |
495 | ); |
496 | |
497 | $workKey = $cacheKey . ':revid:' . $revision->getId(); |
498 | |
499 | return new PoolWorkArticleViewCurrent( |
500 | $workKey, |
501 | $page, |
502 | $revision, |
503 | $parserOptions, |
504 | $this->revisionRenderer, |
505 | $primaryCache, |
506 | $this->lbFactory, |
507 | $this->chronologyProtector, |
508 | $this->loggerSpi, |
509 | $this->wikiPageFactory, |
510 | !( $options & self::OPT_NO_UPDATE_CACHE ), |
511 | (bool)( $options & self::OPT_LINKS_UPDATE ) |
512 | ); |
513 | |
514 | case self::CACHE_SECONDARY: |
515 | $this->statsDataFactory->increment( 'ParserOutputAccess.PoolWork.Old' ); |
516 | $secondaryCache = $this->getSecondaryCache( $parserOptions ); |
517 | $workKey = $secondaryCache->makeParserOutputKey( $revision, $parserOptions ); |
518 | return new PoolWorkArticleViewOld( |
519 | $workKey, |
520 | $secondaryCache, |
521 | $revision, |
522 | $parserOptions, |
523 | $this->revisionRenderer, |
524 | $this->loggerSpi |
525 | ); |
526 | |
527 | default: |
528 | $this->statsDataFactory->increment( 'ParserOutputAccess.PoolWork.Uncached' ); |
529 | $secondaryCache = $this->getSecondaryCache( $parserOptions ); |
530 | $workKey = $secondaryCache->makeParserOutputKeyOptionalRevId( $revision, $parserOptions ); |
531 | return new PoolWorkArticleView( |
532 | $workKey, |
533 | $revision, |
534 | $parserOptions, |
535 | $this->revisionRenderer, |
536 | $this->loggerSpi |
537 | ); |
538 | } |
539 | |
540 | // unreachable |
541 | } |
542 | |
543 | private function getPrimaryCache( ParserOptions $pOpts ): ParserCache { |
544 | if ( $pOpts->getUseParsoid() ) { |
545 | return $this->parserCacheFactory->getParserCache( |
546 | self::PARSOID_PCACHE_NAME |
547 | ); |
548 | } |
549 | |
550 | return $this->parserCacheFactory->getParserCache( |
551 | ParserCacheFactory::DEFAULT_NAME |
552 | ); |
553 | } |
554 | |
555 | private function getSecondaryCache( ParserOptions $pOpts ): RevisionOutputCache { |
556 | if ( $pOpts->getUseParsoid() ) { |
557 | return $this->parserCacheFactory->getRevisionOutputCache( |
558 | self::PARSOID_RCACHE_NAME |
559 | ); |
560 | } |
561 | |
562 | return $this->parserCacheFactory->getRevisionOutputCache( |
563 | ParserCacheFactory::DEFAULT_RCACHE_NAME |
564 | ); |
565 | } |
566 | |
567 | } |