From dbd11e04aa57647bd1c1916603985f8663b191ff Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Wed, 7 Sep 2016 20:26:48 -0700 Subject: [PATCH] resourceloader: Preload WikiModule::getTitleInfo() in batches Test plan: * Request load.php?modules=startup&only=scripts * Debug log receives 1 entry in the 'queries' channel from ResourceLoaderWikiModule, and it comes from preloadTitleInfo. Bug: T46362 Change-Id: I82e215745af6b8446cd69282b2c943afbbd45065 --- includes/resourceloader/ResourceLoader.php | 3 + .../ResourceLoaderWikiModule.php | 92 ++++++++++++++----- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 3cb30bc185..ad1ed49fef 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -140,6 +140,9 @@ class ResourceLoader implements LoggerAwareInterface { } } + // Batched version of ResourceLoaderWikiModule::getTitleInfo + ResourceLoaderWikiModule::preloadTitleInfo( $context, $dbr, $moduleNames ); + // Prime in-object cache for message blobs for modules with messages $modules = []; foreach ( $moduleNames as $name ) { diff --git a/includes/resourceloader/ResourceLoaderWikiModule.php b/includes/resourceloader/ResourceLoaderWikiModule.php index 8033843305..5580306a13 100644 --- a/includes/resourceloader/ResourceLoaderWikiModule.php +++ b/includes/resourceloader/ResourceLoaderWikiModule.php @@ -276,6 +276,10 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { return count( $revisions ) === 0; } + private function setTitleInfo( $key, array $titleInfo ) { + $this->titleInfo[$key] = $titleInfo; + } + /** * Get the information about the wiki pages for a given context. * @param ResourceLoaderContext $context @@ -288,35 +292,77 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { return []; } - $pages = $this->getPages( $context ); - $key = implode( '|', array_keys( $pages ) ); + $pageNames = array_keys( $this->getPages( $context ) ); + sort( $pageNames ); + $key = implode( '|', $pageNames ); if ( !isset( $this->titleInfo[$key] ) ) { - $this->titleInfo[$key] = []; - $batch = new LinkBatch; - foreach ( $pages as $titleText => $options ) { - $batch->addObj( Title::newFromText( $titleText ) ); + $this->titleInfo[$key] = self::fetchTitleInfo( $dbr, $pageNames, __METHOD__ ); + } + return $this->titleInfo[$key]; + } + + private static function fetchTitleInfo( IDatabase $db, array $pages, $fname = __METHOD__ ) { + $titleInfo = []; + $batch = new LinkBatch; + foreach ( $pages as $titleText ) { + $batch->addObj( Title::newFromText( $titleText ) ); + } + if ( !$batch->isEmpty() ) { + $res = $db->select( 'page', + // Include page_touched to allow purging if cache is poisoned (T117587, T113916) + [ 'page_namespace', 'page_title', 'page_touched', 'page_len', 'page_latest' ], + $batch->constructSet( 'page', $db ), + $fname + ); + foreach ( $res as $row ) { + // Avoid including ids or timestamps of revision/page tables so + // that versions are not wasted + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); + $titleInfo[$title->getPrefixedText()] = [ + 'page_len' => $row->page_len, + 'page_latest' => $row->page_latest, + 'page_touched' => $row->page_touched, + ]; } + } + return $titleInfo; + } - if ( !$batch->isEmpty() ) { - $res = $dbr->select( 'page', - // Include page_touched to allow purging if cache is poisoned (T117587, T113916) - [ 'page_namespace', 'page_title', 'page_touched', 'page_len', 'page_latest' ], - $batch->constructSet( 'page', $dbr ), - __METHOD__ - ); - foreach ( $res as $row ) { - // Avoid including ids or timestamps of revision/page tables so - // that versions are not wasted - $title = Title::makeTitle( $row->page_namespace, $row->page_title ); - $this->titleInfo[$key][$title->getPrefixedText()] = [ - 'page_len' => $row->page_len, - 'page_latest' => $row->page_latest, - 'page_touched' => $row->page_touched, - ]; + /** + * @since 1.28 + * @param ResourceLoaderContext $context + * @param IDatabase $db + * @param string[] $modules + */ + public static function preloadTitleInfo( + ResourceLoaderContext $context, IDatabase $db, array $moduleNames + ) { + $rl = $context->getResourceLoader(); + // getDB() can be overridden to point to a foreign database. + // For now, only preload local. In the future, we could preload by wikiID. + $allPages = []; + $wikiModules = []; + foreach ( $moduleNames as $name ) { + $module = $rl->getModule( $name ); + if ( $module instanceof self ) { + $mDB = $module->getDB(); + // Subclasses may disable getDB and implement getTitleInfo differently + if ( $mDB && $mDB->getWikiID() === $db->getWikiID() ) { + $wikiModules[] = $module; + $allPages += $module->getPages( $context ); } } } - return $this->titleInfo[$key]; + $allInfo = self::fetchTitleInfo( $db, array_keys( $allPages ), __METHOD__ ); + foreach ( $wikiModules as $module ) { + $pages = $module->getPages( $context ); + $info = array_intersect_key( $allInfo, $pages ); + $pageNames = array_keys( $pages ); + sort( $pageNames ); + $key = implode( '|', $pageNames ); + $module->setTitleInfo( $key, $info ); + } + return $allInfo; } /** -- 2.20.1